Flutter中数据库的使用教程详解
作者:老李code 时间:2023-12-09 11:16:28
在Flutter开发过程中,我门有时候需要对一些数据进行本地的持久化存储,使用sp文件形式虽然也能解决问题,但是有时数据量较大的时候,显然我们文件形式就不太合适了,这时候我们就需要使用数据库进行存储,我们知道在原生中有系统提供的轻量级sqlite
数据库,在Flutter强大的生态环境中,也有这样一个数据库插件sqflite: ^2.0.2
可以同时在Androud、iOS
中进行数据库操作。
1、 创建数据库:这里我以存储我的搜索历史记录为例。
首先导入:
import 'package:sqflite/sqflite.dart';
这里我创建了一个数据库帮助类,为了以后数据库更新、升级等作准备:
代码实现:主要是对Database这个类的获取进行了封装。
/// 数据库帮助类
class DbHelper {
final String path = "laoli.db"; // 数据库名称 一般不变
//数据库中的表名字 这里是我存错历史搜索记录的表
static final searchTab = "SearchHistory";
//私有构造
DbHelper._();
static DbHelper? _instance;
static DbHelper get instance => _getInstance();
factory DbHelper() {
return instance;
}
static DbHelper _getInstance() {
if (_instance == null) {
_instance = DbHelper._();
}
return _instance ?? DbHelper._();
}
/// 数据库默认存储的路径
/// SQLite 数据库是文件系统中由路径标识的文件。如果是relative,
/// 这个路径是相对于 获取的路径getDatabasesPath(),
/// Android默认的数据库目录,
/// iOS/MacOS的documents目录。
Future<Database>? _db;
Future<Database>? getDb() {
_db ??= _initDb();
return _db;
}
// Guaranteed to be called only once.保证只调用一次
Future<Database> _initDb() async {
// 这里是我们真正创建数据库的地方 vserion代表数据库的版本,如果版本改变
//,则db会调用onUpgrade方法进行更新操作
final db =
await openDatabase(this.path, version: 1, onCreate: (db, version) {
// 数据库创建完成
// 创建表 一个自增id 一个text
db.execute("create table $searchTab (id integer primary key autoincrement, name text not null)");
}, onUpgrade: (db, oldV, newV) {
// 升级数据库调用
/// db 数据库
/// oldV 旧版本号
// newV 新版本号
// 升级完成就不会在调用这个方法了
});
return db;
}
// 关闭数据库
close() async {
await _db?.then((value) => value.close());
}
}
在java
后台开发过程中,数据库肯定都会分层设计,这样的好处可以在使用的过程中极大的提高代码的健壮性以及降低后期的维护成本,在移动前端虽然我们用数据库的地方跟后台相比少之又少,但是我还是建议也对数据库进行分层处理操作,虽然不分层也能实现,但是这样也可以降低我们的对于代码的维护成本以及良好的编程习惯。废话不多说,接下来我们需要创建处理数据的dao
层。
这里sqflite
封装了一些常用的sql
语法,比如增删改查,我们就不需要自己去写sql语法了,这里我简答封装了下增删改查的方法。
具体代码:
/// 数据操作类
class DbSearchHistoryDao {
/// 增
static insert(String text) {
// 去重
queryAll().then((value) {
bool isAdd = true;
for (var data in value) {
if (data.name == text) {
isAdd = false;
break;
}
}
if (isAdd) {
DbHelper.instance.getDb()?.then((value) => value.insert(
DbHelper.searchTab,
DbSearchHotBean(name: text).toJson(),
));
}
});
}
/// 删 全部
static deleteAll() {
DbHelper.instance.getDb()?.then((value) => value.delete(
DbHelper.searchTab,
));
}
/// 更新数据 通过id更新表内具体行的数据
static update(DbSearchHotBean dbSearchHotBean) {
DbHelper.instance.getDb()?.then((value) => value.update(
DbHelper.searchTab,
dbSearchHotBean.toJson(),//具体更新的数据
where: "id = ?"//通过id查找需要更新的数据
,whereArgs: [dbSearchHotBean.id]
));
}
/// 通过name查具体的实体类
static Future<DbSearchHotBean?> getBean(String name) async {
var db = await DbHelper.instance.getDb();
var maps = await db?.query(DbHelper.searchTab,
columns: ['id','name'],// 获取实体类的哪些字段 默认全部
where: 'name = ?',//通过实体类中的name字段
whereArgs: [name]);//具体name的值 限定数据
if(maps!=null && maps.length > 0) {
return DbSearchHotBean.fromJson(maps.first);
}
return null;
}
/// 查 全部all
static Future<List<DbSearchHotBean>> queryAll() async {
List<DbSearchHotBean> list = [];
await DbHelper.instance
.getDb()
?.then((db) => db.query(DbHelper.searchTab).then((value) {
for (var data in value) {
list.add(DbSearchHotBean.fromJson(data));
}
}));
return list;
}
}
实体类:虽然只有一个字段,但是创建实体类方便以后扩展。
class DbSearchHotBean {
int? id;
String? name; // 搜索词
DbSearchHotBean({this.id,required this.name});
DbSearchHotBean.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
}
Map<String, String?> toJson() {
var map = <String, String?>{};
map['id'] = id?.toString() ;
map['name'] = name ?? "";
return map;
}
}
具体用法就非常简单了:
增:DbSearchHistoryDao.insert(”搜索词“);
删全部:DbSearchHistoryDao.deleteAll();
改:例如将水改为火, 找到水的实体通过自增id修改name
DbSearchHistoryDao.getBean("水").then((value){
if(value!=null){
DbSearchHistoryDao.update(DbSearchHotBean(id: value.id,name: "火"));
}
});
查全部:await DbSearchHistoryDao.queryAll();
到这里数据库的基本用法就介绍完了,当然部分操作比如删指定数据,批量修改、批量删除等操作可以用 到批处理操作,这里就不过多介绍了,有需要的可以查看作者文档。链接
batch = db.batch();
batch.insert('Test', {'name': 'item'});
batch.update('Test', {'name': 'new_item'}, where: 'name = ?', whereArgs: ['item']);
batch.delete('Test', where: 'name = ?', whereArgs: ['item']);
results = await batch.commit();
总结
数据库操作总体上没什么难度,但是当我们数据量比较多的时候,数据表结构的设计就有一定的技术含量了,还有就是我们对于一些sql语句的掌握,因为此插件帮我们封装了常用的功能,如果有比较特殊的需求,还是需要我们掌握一定的sql语法才行,这里就简单的介绍一些常用的方法,在移动前端估计也基本够用了~
来源:https://juejin.cn/post/7084536128077824037