前言
数据库存储是我们常用的存储方式之一, 对大批量数据有增, 删, 改, 查操作需求时, 我们就会想到使用数据库, Flutter 中提供了一个 sqflite 插件供我们用于大量数据执行 CRUD 操作. 本篇我们就来一起学习 sqflite 的使用.
sqflite 使用
引入插件
在 pubspec.YAML 文件中添加 path_provider 插件, 最新版本为 1.0.0, 如下:
- dependencies:
- flutter:
- sdk: flutter
- #sqflite 插件
- sqflite: 1.0.0
然后命令行执行 flutter packages get 即可将插件下载到本地.
数据库操作方法介绍
1. 插入操作
插入数据操作有两个方法:
- Future<int> rawInsert(String sql, [List<dynamic> arguments]);
- Future<int> insert(String table, Map<String, dynamic> values,
- {String nullColumnHack, ConflictAlgorithm conflictAlgorithm});
rawInsert 方法第一个参数为一条插入 sql 语句, 可以使用? 作为占位符, 通过第二个参数填充数据.
insert 方法第一个参数为操作的表名, 第二个参数 map 中是想要添加的字段名和对应字段值.
2. 查询操作
查询操作同样实现了两个方法:
- Future<List<Map<String, dynamic>>> query(String table,
- {bool distinct,
- List<String> columns,
- String where,
- List<dynamic> whereArgs,
- String groupBy,
- String having,
- String orderBy,
- int limit,
- int offset});
- Future<List<Map<String, dynamic>>> rawQuery(String sql,
- [List<dynamic> arguments]);
query 方法第一个参数为操作的表名, 后边的可选参数依次表示是否去重, 查询字段, WHERE 子句 (可使用? 作为占位符),WHERE 子句占位符参数值, GROUP BY 子句, HAVING 子句, ORDER BY 子句, 查询的条数, 查询的偏移位等.
rawQuery 方法第一个参数为一条查询 sql 语句, 可以使用? 作为占位符, 通过第二个参数填充数据.
3. 修改操作
修改操作同样实现了两个方法:
- Future<int> rawUpdate(String sql, [List<dynamic> arguments]);
- Future<int> update(String table, Map<String, dynamic> values,
- {String where,
- List<dynamic> whereArgs,
- ConflictAlgorithm conflictAlgorithm});
rawUpdate 方法第一个参数为一条更新 sql 语句, 可以使用? 作为占位符, 通过第二个参数填充数据.
update 方法第一个参数为操作的表名, 第二个参数为修改的字段和对应值, 后边的可选参数依次表示 WHERE 子句 (可使用? 作为占位符),WHERE 子句占位符参数值, 发生冲突时的操作算法 (包括回滚, 终止, 忽略等等).
4. 删除操作
修改操作同样实现了两个方法:
- Future<int> rawDelete(String sql, [List<dynamic> arguments]);
- Future<int> delete(String table, {
- String where, List<dynamic> whereArgs
- });
rawDelete 方法第一个参数为一条删除 sql 语句, 可以使用? 作为占位符, 通过第二个参数填充数据.
delete 方法第一个参数为操作的表名, 后边的可选参数依次表示 WHERE 子句 (可使用? 作为占位符),WHERE 子句占位符参数值.
举个栗子
我们以图书管理系统来举例.
首先, 我们创建一个书籍类, 包括书籍 ID, 书名, 作者, 价格, 出版社等信息.
- final String tableBook = 'book';
- final String columnId = '_id';
- final String columnName = 'name';
- final String columnAuthor = 'author';
- final String columnPrice = 'price';
- final String columnPublishingHouse = 'publishingHouse';
- class Book {
- int id;
- String name;
- String author;
- double price;
- String publishingHouse;
- Map<String, dynamic> toMap() {
- var map = <String, dynamic>{
- columnName: name,
- columnAuthor: author,
- columnPrice: price,
- columnPublishingHouse: publishingHouse
- };
- if (id != null) {
- map[columnId] = id;
- }
- return map;
- }
- Book();
- Book.fromMap(Map<String, dynamic> map) {
- id = map[columnId];
- name = map[columnName];
- author = map[columnAuthor];
- price = map[columnPrice];
- publishingHouse = map[columnPublishingHouse];
- }
- }
其次, 我们开始实现数据库相关操作:
1. 创建数据库文件和对应的表
- // 获取数据库文件的存储路径
- var databasesPath = await getDatabasesPath();
- String path = join(databasesPath, 'demo.db');
- // 根据数据库文件路径和数据库版本号创建数据库表
- db = await openDatabase(path, version: 1,
- onCreate: (Database db, int version) async {
- await db.execute('''
- CREATE TABLE $tableBook (
- $columnId INTEGER PRIMARY KEY,
- $columnName TEXT,
- $columnAuthor TEXT,
- $columnPrice REAL,
- $columnPublishingHouse TEXT)
- ''');
- });
2. CRUD 操作实现
- // 插入一条书籍数据
- Future<Book> insert(Book book) async {
- book.id = await db.insert(tableBook, book.toMap());
- return book;
- }
- // 查找所有书籍信息
- Future<List<Book>> queryAll() async {
- List<Map> maps = await db.query(tableBook, columns: [
- columnId,
- columnName,
- columnAuthor,
- columnPrice,
- columnPublishingHouse
- ]);
- if (maps == null || maps.length == 0) {
- return null;
- }
- List<Book> books = [];
- for (int i = 0; i <maps.length; i++) {
- books.add(Book.fromMap(maps[i]));
- }
- return books;
- }
- // 根据 ID 查找书籍信息
- Future<Book> getBook(int id) async {
- List<Map> maps = await db.query(tableBook,
- columns: [
- columnId,
- columnName,
- columnAuthor,
- columnPrice,
- columnPublishingHouse
- ],
- where: '$columnId = ?',
- whereArgs: [id]);
- if (maps.length> 0) {
- return Book.fromMap(maps.first);
- }
- return null;
- }
- // 根据 ID 删除书籍信息
- Future<int> delete(int id) async {
- return await db.delete(tableBook, where: '$columnId = ?', whereArgs: [id]);
- }
- // 更新书籍信息
- Future<int> update(Book book) async {
- return await db.update(tableBook, book.toMap(),
- where: '$columnId = ?', whereArgs: [book.id]);
- }
3. 关闭数据库
数据库对象使用完之后要在适当的时候关闭掉, 可在 helper 类中实现以下方法.
Future close() async => db.close();
运行效果:
事务
sqflite 同时支持事务, 通过事务可以将多条原子操作放在一起执行, 保证操作要么全部执行完成, 要么都不执行. 比如有两条书籍数据必须全部插入书库中才算添加成功, 则使用如下方法
- Future<bool> insertTwoBook(Book book1, Book book2) async {
- return await db.transaction((Transaction txn) async {
- book1.id = await db.insert(tableBook, book1.toMap());
- book2.id = await db.insert(tableBook, book2.toMap());
- print('book1.id = ${book1.id}, book2.id = ${book2.id}');
- return book1.id != null && book2.id != null;
- });
- }
写在最后
以上介绍了 sqflite 中我们常用的几个操作, 有了 sqflite 我们就可以开发更丰富的应用程序, 在开发实践中大家遇到任何问题都可以给我们发消息反馈, 大家一起交流探讨共同进步. 针对一些用户的反馈我们将在下一篇介绍 Flutter 的代码调试.
说明:
来源: https://juejin.im/post/5c81e48c6fb9a049b07e2534