Flutter中SQFLite数据库:
支持事务的批量操作
支持增删改查
在iOS和Android双端后台线程中执行数据库操作
使用方式:
1,添加依赖
dependencies:... sqflite: any
2,导入文件:
import 'package:sqflite/sqflite.dart';
3, //创建数据库
Future
_createNewDb(String dbName) async { //获取数据库文件路径
var dbPath = await getDatabasesPath();
print('dbPath:' + dbPath);
String path = join(dbPath, dbName);
if (await new Directory(dirname(path)).exists()) {
await deleteDatabase(path);
} else {
try { await new Directory(dirname(path)).create(recursive: true);
} catch (e) { print(e);
}
}
return path;
}
_create() async {
dbPath = await _createNewDb(dbName);
Database db = await openDatabase(dbPath);
await db.execute(sql_createTable);
await db.close();
setState(() {
_result = '创建user.db成功,创建user_table成功'; });
}
//打开数据库,获取数据库对象
_open() async {
if(null == dbPath){ var path = await getDatabasesPath();
dbPath = join(path, dbName); print('dbPath:' + dbPath);
}
return await openDatabase(dbPath);
}
4,删除数据库
await deleteDatabase(path);
5,打开数据库并创建一张表
Database database = await openDatabase(path, version: 1, onCreate: (Database db, int version) async { await db.execute( "CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT, value INTEGER, num REAL)");
});
// 插入数据库的两种方式
1,Future
rawInsert(String sql, [List arguments]); 2,Future
insert(String table, Map values, {String nullColumnHack, ConflictAlgorithm conflictAlgorithm}); rawInsert方法第一个参数为一条插入sql语句,可以使用?作为占位符,通过第二个参数填充数据。 insert方法第一个参数为操作的表名,第二个参数map中是想要添加的字段名和对应字段值。
示例:
await database.transaction((txn) async {
int id1 = await txn.rawInsert( 'INSERT INTO Test(name, value, num) VALUES("some name", 1234, 456.789)');
print("inserted1: $id1");
// 查询操作的两种方法
Future
>> query(String table,
{bool distinct,
List
columns, String where,
List
whereArgs, String groupBy,
String having,
String orderBy,
intlimit,
intoffset});
Future
>> rawQuery(String sql, [List
arguments]); query方法第一个参数为操作的表名,后边的可选参数依次表示是否去重、查询字段、WHERE子句(可使用?作为占位符)、WHERE子句占位符参数值、GROUP BY子句、HAVING子句、ORDER BY子句、查询的条数、查询的偏移位等。 rawQuery方法第一个参数为一条查询sql语句,可以使用?作为占位符,通过第二个参数填充数据。
示例如下:
await database.transaction ((txn) async { int id1 = await txn.rawInsert( 'INSERT INTO Test(name, value, num) VALUES("some name", 1234, 456.789)'); print("inserted1: $id1"); int id2 = await txn.rawInsert( 'INSERT INTO Test(name, value, num) VALUES(?, ?, ?)', ["another name", 12345678, 3.1416]); print("inserted2: $id2");});
// 更新的两种方式
Future
rawUpdate(String sql, [List arguments]); Future update(String table, Map values, {String where, List whereArgs, ConflictAlgorithm conflictAlgorithm}); rawUpdate方法第一个参数为一条更新sql语句,可以使用?作为占位符,通过第二个参数填充数据。
update方法第一个参数为操作的表名,第二个参数为修改的字段和对应值,后边的可选参数依次表示WHERE子句(可使用?作为占位符)、WHERE子句占位符参数值、发生冲突时的操作算法(包括回滚、终止、忽略等等)。
示例如下:
int count =awaitdatabase.rawUpdate(
UPDATE Test SET name = ?, VALUE = ? WHERE name = ?',["updated name","9876","some name"]);
print("updated: $count");
// 删除的两种方式
Future rawDelete(String sql, [List arguments]);
Future delete(String table, {String where, List whereArgs});
rawDelete方法第一个参数为一条删除sql语句,可以使用?作为占位符,通过第二个参数填充数据。
delete方法第一个参数为操作的表名,后边的可选参数依次表示WHERE子句(可使用?作为占位符)、WHERE子句占位符参数值。
示例如下:
count =awaitdatabase.rawDelete('DELETE FROM Test WHERE name = ?',['an
other name']);
assert(count==1);
// 获取Test表的数据
List list = awaitdatabase.rawQuery('SELECT * FROM Test');List expectedList=[{"name":"updated name","id":1,"value":9876,"num":456.789},{"name":"another name","id":2,"value":12345678,"num":3.1416}];
print(list);
print(expectedList);
assert(constDeepCollectionEquality().equals(list, expectedList));
// 获取记录的数量
count = Sqflite.firstIntValue(awaitdatabase.rawQuery("SELECT COUNT(*) FROM Test"));
assert(count==2);
// 关闭数据库
await database.close();
Future close() async => db.close();
使用示例如下所示:
其中有一些注意事项:
1,Transcaction
2,支持批量操作
但是这里注意,这些操作返回结果,都会有一些开销,如果不考虑结果,可以使用。
事务期间,直到事务被提交,批量操作才能提交。
3,表和列的名字
通常避免使用SQLite关键字作为表名或者列名,例如以下其中之一。
如果必须使用如上,需要使用双引号转义,例如:
4,支持的列类型
首先,我们创建一个书籍类,包括书籍ID、书名、作者、价格、出版社等信息。
示例二:
finalString tableBook = 'book';finalString columnId = '_id';
finalString columnName = 'name';
finalString columnAuthor = 'author';
finalString columnPrice = 'price';
finalString columnPublishingHouse = 'publishingHouse';
classBook {
intid;
String name;
String author;
doubleprice;
String publishingHouse;
Map
toMap() { var map =
{ columnName: name,
columnAuthor: author,
columnPrice: price,
columnPublishingHouse: publishingHouse
};
if(id != null) {
map[columnId] = id;
}
returnmap;
}
Book();
Book.fromMap(Map
map) { id = map[columnId];
name = map[columnName];
author = map[columnAuthor];
price = map[columnPrice];
publishingHouse = map[columnPublishingHouse];
}
}
2,创建对应的数据库文件和表
// 获取数据库文件的存储路径
var databasesPath = await getDatabasesPath();
String path = join(databasesPath, 'demo.db');
//根据数据库文件路径和数据库版本号创建数据库表
db = await openDatabase(path, version: 1,
onCreate: (Database db, intversion) async {
await db.execute('''
CREATE TABLE $tableBook (
$columnId INTEGER PRIMARY KEY,
$columnName TEXT,
$columnAuthor TEXT,
$columnPrice REAL,
$columnPublishingHouse TEXT)
''');
});
3,CRUD实现
// 插入一条书籍数据Future
insert(Book book) async { book.id = await db.insert(tableBook, book.toMap());
returnbook;
}
// 查找所有书籍信息
Future
> queryAll() async {
List
columnId,
columnName,
columnAuthor,
columnPrice,
columnPublishingHouse
]);
if(maps == null|| maps.length == 0) {
returnnull;
}
List
books = []; for(inti = 0; i < maps.length; i++) {
books.add(Book.fromMap(maps[i]));
}
returnbooks;
}
// 根据ID查找书籍信息
Future
getBook(intid) async { List
columns: [
columnId,
columnName,
columnAuthor,
columnPrice,
columnPublishingHouse
],
where: '$columnId = ?',
whereArgs: [id]);
if(maps.length > 0) {
returnBook.fromMap(maps.first);
}
returnnull;
}
// 根据ID删除书籍信息
Future
delete(intid) async { returnawait db.delete(tableBook, where: '$columnId = ?', whereArgs: [id]);
}
// 更新书籍信息
Future
update(Book book) async { returnawait db.update(tableBook, book.toMap(),
where: '$columnId = ?', whereArgs: [book.id]);
}
4,关闭数据库,上文中已提示
5,CRUDUtils
_add() async { Database db = await _open(); String sql = "INSERT INTO user_table(username,pwd) VALUES('$username','$pwd')"; //开启事务 await db.transaction((txn) async { int id = await txn.rawInsert(sql); }); await db.close(); setState(() { _result = "插入username=$username,pwd=$pwd数据成功"; }) ; } _delete() async { Database db = await _open(); //删除最近一条 String sql = "DELETE FROM user_table where id in (select id from user_table order by id desc limit 1)"; int count = await db.rawDelete(sql); await db.close(); setState(() { if (count == 1) { _result = "删除成功,请查看"; } else { _result = "删除0条数据或删除失败,请看log"; } }); } _update() async { Database db = await _open(); String sql = "UPDATE user_table SET pwd = ? WHERE id = ?"; int count = await db.rawUpdate(sql, ["654321", '1']); print(count); await db.close(); setState(() { _result = "更新数据成功,请查看"; }); } //批量增、改、删数据 _batch() async { Database db = await _open(); var batch = db.batch(); batch.insert("user_table", {"username": "batchName1"}); batch.update("user_table", {"username": "batchName2"}, where: "username = ?",whereArgs: ["batchName1"]); batch.delete("user_table", where: "username = ?", whereArgs: ["Leon"]); //返回每个数据库操作的结果组成的数组 [6, 3, 0]:新增返回id=6,修改了3条数据,删除了0条数据 var results = await batch.commit(); await db.close(); setState(() { _result = "批量增、改数据成功 "+results.toString(); }); } _queryNum() async { Database db = await _open(); int count = Sqflite.firstIntValue( await db.rawQuery(sql_query_count)); await db.close(); setState(() { _result = "数据条数:$count"; }); } _query() async { Database db = await _open(); List
数据库的创建、打开,都需要先获取数据库文件的路径,获取到path之后Database db = await openDatabase(dbPath);获取数据库对象,注意数据库的操作全都是异步的,要用关键字await。