本文共 6309 字,大约阅读时间需要 21 分钟。
Flutter原生是没有支持数据库操作的,它使用SQLlit插件来使应用具有使用数据库的能力。其实就是Flutter通过插件来与原生系统沟通,来进行数据库操作。
平台支持
使用案例
添加依赖
为了使用 SQLite 数据库,首先需要导入 sqflite 和 path 这两个 package
dependencies: sqflite: ^1.3.0 path:版本号复制代码
使用
导入 sqflite.dart
import 'dart:async';import 'package:path/path.dart';import 'package:sqflite/sqflite.dart';复制代码
打开数据库
SQLite数据库就是文件系统中的文件。如果是相对路径,则该路径是getDatabasesPath()所获得的路径,该路径关联的是Android上的默认数据库目录和iOS上的documents目录。
var db = await openDatabase('my_db.db');复制代码
许多时候我们使用数据库时不需要手动关闭它,因为数据库会在程序关闭时被关闭。如果你想自动释放资源,可以使用如下方式:
await db.close();复制代码
使用 sqflite package 里的 getDatabasesPath 方法并配合 path package里的 join 方法定义数据库的路径。使用path包中的join方法是确保各个平台路径正确性的最佳实践。
var databasesPath = await getDatabasesPath();String path = join(databasesPath, 'demo.db');复制代码
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)');});复制代码
在事务中向表中插入几条数据
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');});复制代码
删除表中的一条数据
count = await database .rawDelete('DELETE FROM Test WHERE name = ?', ['another name']);复制代码
修改表中的数据
int count = await database.rawUpdate('UPDATE Test SET name = ?, value = ? WHERE name = ?', ['updated name', '9876', 'some name']);print('updated: $count');复制代码
查询表中的数据
// Get the recordsList
查询表中存储数据的总条数
count = Sqflite.firstIntValue(await database.rawQuery('SELECT COUNT(*) FROM Test'));复制代码
await database.close();复制代码
await deleteDatabase(path);复制代码
//字段final String tableTodo = 'todo';final String columnId = '_id';final String columnTitle = 'title';final String columnDone = 'done';//对应类class Todo { int id; String title; bool done; //把当前类中转换成Map,以供外部使用 MaptoMap() { var map = { columnTitle: title, columnDone: done == true ? 1 : 0 }; if (id != null) { map[columnId] = id; } return map; } //无参构造 Todo(); //把map类型的数据转换成当前类对象的构造函数。 Todo.fromMap(Map map) { id = map[columnId]; title = map[columnTitle]; done = map[columnDone] == 1; }}复制代码
class TodoProvider { Database db; Future open(String path) async { db = await openDatabase(path, version: 1, onCreate: (Database db, int version) async { await db.execute(''' create table $tableTodo ( $columnId integer primary key autoincrement, $columnTitle text not null, $columnDone integer not null) '''); }); } //向表中插入一条数据,如果已经插入过了,则替换之前的。 Futureinsert(Todo todo) async { todo.id = await db.insert(tableTodo, todo.toMap(),conflictAlgorithm: ConflictAlgorithm.replace,); return todo; } Future getTodo(int id) async { List maps = await db.query(tableTodo, columns: [columnId, columnDone, columnTitle], where: '$columnId = ?', whereArgs: [id]); if (maps.length > 0) { return Todo.fromMap(maps.first); } return null; } Future delete(int id) async { return await db.delete(tableTodo, where: '$columnId = ?', whereArgs: [id]); } Future update(Todo todo) async { return await db.update(tableTodo, todo.toMap(), where: '$columnId = ?', whereArgs: [todo.id]); } Future close() async => db.close();}复制代码
List> records = await db.query('my_table');复制代码
MapmapRead = records.first;复制代码
mapRead['my_column'] = 1;// Crash... `mapRead` is read-only复制代码
// 根据上面的map创建一个map副本Mapmap = Map .from(mapRead);// 在内存中修改此副本中存储的字段值map['my_column'] = 1;复制代码
// Convert the Listinto a List . return List.generate(maps.length, (i) { return Todo( id: maps[i][columnId], title: maps[i][columnTitle], done: maps[i][columnDown], ); });复制代码
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();复制代码
获取每个操作的结果是需要成本的(插入的Id以及更新和删除的更改数)。如果您不关心操作的结果则可以执行如下操作关闭结果的响应
await batch.commit(noResult: true);复制代码
在事务中进行批处理操作,当事务提交后才会提交批处理。
await database.transaction((txn) async { var batch = txn.batch(); // ... // commit but the actual commit will happen when the transaction is committed // however the data is available in this transaction await batch.commit(); // ...});复制代码
默认情况下批处理中一旦出现错误就会停止(未执行的语句则不会被执行了),你可以忽略错误,以便后续操作的继续执行。
await batch.commit(continueOnError: true);复制代码
通常情况下我们应该避免使用SQLite关键字来命名表名称和列名称。如:
"add","all","alter","and","as","autoincrement","between","case","check","collate","commit","constraint","create","default","deferrable","delete","distinct","drop","else","escape","except","exists","foreign","from","group","having","if","in","index","insert","intersect","into","is","isnull","join","limit","not","notnull","null","on","or","order","primary","references","select","set","table","then","to","transaction","union","unique","update","using","values","when","where"复制代码
SQLite类型 | dart类型 | 值范围 |
---|---|---|
integer | int | 从-2 ^ 63到2 ^ 63-1 |
real | num | |
text | String | |
blob | Uint8List |
转载地址:http://pexqz.baihongyu.com/