欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Flutter持久化存储之数据库存储(sqflite)详解

程序员文章站 2022-06-03 19:16:59
前言 数据库存储是我们常用的存储方式之一,对大批量数据有增、删、改、查操作需求时,我们就会想到使用数据库,flutter中提供了一个sqflite插件供我们用于大量数...

前言

数据库存储是我们常用的存储方式之一,对大批量数据有增、删、改、查操作需求时,我们就会想到使用数据库,flutter中提供了一个sqflite插件供我们用于大量数据执行crud操作。本篇我们就来一起学习sqflite的使用。

sqflite是一款轻量级的关系型数据库,类似sqlite。

在flutter平台我们使用sqflite库来同时支持android 和ios。

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的代码调试。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。