1. 首页
  2. 资源下载
  3. Flutter 插件

Flutter plugin for SQLite

SQLite的Flutter插件,一个独立的,高可靠性的嵌入式SQL数据库引擎。

sqflite 

Flutter的 SQLite插件。支持iOS和Android。

  • 支持交易和批次
  • 打开期间自动版本管理
  • 插入/查询/更新/删除查询的助手
  • 在iOS和Android上的后台线程中执行数据库操作

入门

在你的flutter项目中添加依赖项:

dependencies:
  ...
  sqflite: ^1.1.0

有关Flutter入门的帮助,请查看在线 文档

用法示例

进口 sqflite.dart

import 'package:sqflite/sqflite.dart';

原始SQL查询

演示用于执行Raw SQL查询的代码

// Get a location using getDatabasesPath
var databasesPath = await getDatabasesPath();
String path = join(databasesPath, 'demo.db');

// Delete the database
await deleteDatabase(path);

// open the database
Database database = await openDatabase(path, version: 1,
    onCreate: (Database db, int version) async {
  // When creating the db, create the table
  await db.execute(
      'CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT, value INTEGER, num REAL)');
});

// Insert some records in a transaction
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');
});

// Update some record
int count = await database.rawUpdate(
    'UPDATE Test SET name = ?, VALUE = ? WHERE name = ?',
    ['updated name', '9876', 'some name']);
print('updated: $count');

// Get the records
List<Map> list = await database.rawQuery('SELECT * FROM Test');
List<Map> 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(const DeepCollectionEquality().equals(list, expectedList));

// Count the records
count = Sqflite
    .firstIntValue(await database.rawQuery('SELECT COUNT(*) FROM Test'));
assert(count == 2);

// Delete a record
count = await database
    .rawDelete('DELETE FROM Test WHERE name = ?', ['another name']);
assert(count == 1);

// Close the database
await database.close();

SQL助手

使用帮助程序的示例

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<String, dynamic> toMap() {
    var map = <String, dynamic>{
      columnTitle: title,
      columnDone: done == true ? 1 : 0
    };
    if (id != null) {
      map[columnId] = id;
    }
    return map;
  }

  Todo();

  Todo.fromMap(Map<String, dynamic> 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)
''');
    });
  }

  Future<Todo> insert(Todo todo) async {
    todo.id = await db.insert(tableTodo, todo.toMap());
    return todo;
  }

  Future<Todo> getTodo(int id) async {
    List<Map> 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<int> delete(int id) async {
    return await db.delete(tableTodo, where: '$columnId = ?', whereArgs: [id]);
  }

  Future<int> update(Todo todo) async {
    return await db.update(tableTodo, todo.toMap(),
        where: '$columnId = ?', whereArgs: [todo.id]);
  }

  Future close() async => db.close();
}

阅读结果

假设以下读取结果:

List<Map<String, dynamic>> records = await db.query('my_table');

生成的地图项目是只读的

// get the first record
Map<String, dynamic> mapRead = records.first;
// Update it in memory...this will throw an exception
mapRead['my_column'] = 1;
// Crash... `mapRead` is read-only

如果要在内存中修改它,则需要创建新地图:

// get the first record
Map<String, dynamic> map = Map<String, dynamic>.from(mapRead);
// Update it in memory now
map['my_column'] = 1;

交易

不要使用数据库,而只使用事务中的Transaction对象来访问数据库

await database.transaction((txn) async {
  // Ok
  await txn.execute('CREATE TABLE Test1 (id INTEGER PRIMARY KEY)');
  
  // DON'T  use the database object in a transaction
  // this will deadlock!
  await database.execute('CREATE TABLE Test2 (id INTEGER PRIMARY KEY)');
});

如果回调没有引发错误,则提交事务。如果抛出错误,则取消该事务。因此,以一种方式回滚事务就是抛出异常。

批量支持

要避免dart和本机代码之间的乒乓,您可以使用Batch

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和更新和删除的更改次数),尤其是在执行额外SQL请求的Android上。如果您不关心结果并担心大批量的性能,您可以使用

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"

助手将逃避名称即

db.query('table')

将等同于在表名周围手动添加双引号(这里容易引起混淆table

db.rawQuery('SELECT * FROM "table"');

然而,在任何其他原料陈述(包括orderBywheregroupBy),确保正确转义名称中使用双引号。例如,请参阅下面的列名称group未在列参数中转义,但在where参数中进行转义。

db.query('table', columns: ['group'], where: '"group" = ?', whereArgs: ['my_group']);

支持的SQLite类型

尚未对值进行有效性检查,因此请避免使用不受支持的类型https://www.sqlite.org/datatype3.html

DateTime不是受支持的SQLite类型。我个人将它们存储为int(millisSinceEpoch)或字符串(iso8601)

bool不是受支持的SQLite类型。使用INTEGER和0和1值。

INTEGER 

  • 飞镖类型: int
  • 支持的值:从-2 ^ 63到2 ^ 63 - 1

真实

  • 飞镖类型: num

文字

  • 飞镖类型: String

BLOB 

  • 飞镖类型: Uint8List
  • List<int>支持Dart类型但不推荐(慢转换)

当前问题

  • 由于事务在SQLite(线程)中的工作方式,不支持并发读写事务。所有呼叫当前都已同步,事务块是独占的。我认为支持并发访问的基本方法是多次打开数据库,但它只能在iOS上运行,因为Android会重用相同的数据库对象。我还认为本机线程可能是一个潜在的未来解决方案,但在Android访问另一个线程中的数据库时,在事务中被阻止...
  • 目前INTEGER仅限于-2 ^ 63到2 ^ 63 - 1(尽管Android支持更大的)

1.1.1 

  • 使用mixin并提取非颤振代码 sqlite_api.dart
  • 弃用SqfliteOptions仅在内部使用

1.1.0 

  • 打破变革。从已弃用的原始Android支持库迁移到AndroidX。这不应导致任何功能更改,但如果他们使用原始支持库,则需要使用此插件的任何Android应用程序也进行迁移。 您可能会说应该将版本提升到2.0.0,但这只是一个工具问题,代码没有改变。这是flutter插件中所做更改的副本

1.0.0 

  • 升级0.13.0版本为1.0.0
  • 删除已弃用的API(applyBatch,apply)

0.13.0 

  • 添加continueOrError对批次的支持

0.12.0 

  • 添加iOS目标C前缀以防止冲突
  • 在iOS上创建数据库的目录(如果它不存在)

0.11.2 

  • Database.isOpen一旦数据库关闭,add 将变为false

0.11.1 

  • 添加Sqlflite.hex以允许查询blob字段

0.11.0 

  • 添加getDatabasesPath以用作创建数据库的基本位置
  • 警告:数据库现在默认为单个实例(基于path),以便singleInstance = false在打开数据库时使用旧行为
  • dart2稳定的支持

0.10.0 

  • 准备1.0
  • 删除已弃用的方法(可重入事务)
  • 加 Transaction.batch
  • 显示开发人员警告以防止死锁

0.9.0 

  • 支持内存数据库(:memory:路径)
  • 支持单个实例
  • 用于处理新选项的新数据库工厂

0.8.9 

  • 升级到sdk 27

0.8.8 

  • 允许测试约束异常

0.8.6 

  • 更好的SQL错误报告
  • 捕获android原生错误
  • 删除数据库失败时不再打印错误

0.8.4 

  • 使用添加只读支持 openReadOnlyDatabase

0.8.3 

  • 允许在事务使用期间运行批处理 Transaction.applyBatch
  • 恢复Batch.commit在事务外部使用

0.8.2 

  • 虽然已经在事务中,但允许在打开期间创建嵌套事务

0.8.1 

  • Transaction不使用Zone的新机制(现在仍支持旧机制)
  • 开始使用Batch.apply而不是Batch.commit
  • 弃用Database.inTransaction并且Database.synchronized不再使用区域

0.7.1 

  • 添加Batch.queryBatch.rawQueryBatch.execute
  • 将查询结果打包为colums / rows而不是List <Map>

0.7.0 

  • 添加支持 --preview-dart-2

0.6.2 + 1 

  • 向pubspec.yaml添加更长的描述

0.6.2 

  • 修复travis警告

0.6.1 

  • 将Flutter SDK约束添加到pubspec.yaml

0.6.0 

  • 添加支持onConfigure以允许数据库配置

0.5.0 

  • 在insert / update / query / delete中需要时转义表和列名
  • 在新的sql.dart中导出ConflictAlgorithm,escapeName,unescapeName

0.4.0 

  • 添加对Batch的支持(插入/更新/删除)

0.3.1 

  • 删除临时并发实验

0.3.0 

2018年1月4日

  • 打破变革。升级到Gradle 4.1和Android Studio Gradle插件3.0.1。较旧的Flutter项目也需要升级他们的Gradle设置才能使用此版本的插件。说明可以在这里找到 。

0.2.4 

  • 对synchronized的依赖更新为> = 1.1.0

0.2.3 

  • 让Android在同一个线程中发送响应然后调用者,以防止发生错误时出现意外行为

0.2.2 

  • 在Android上修复未经检查的警告

0.2.0 

  • 使用NSOperationQueue进行iOS上的所有数据库操作
  • 将ThreadHandler用于Android上的所有数据库操作

0.0.3 

  • 添加异常处理

0.0.2 

  • 根据Razvan Lung建议添加sqlite助手

0.0.1 

  • 初步实验

sqflite_example 

演示如何使用sqflite插件

快速测试

flutter run

具体的app入口点

flutter run -t lib/main.dart

将此包用作库

1.依靠它

将其添加到包的pubspec.yaml文件中:


dependencies:
  sqflite: ^1.1.1

2.安装它

您可以从命令行安装软件包:

与Fluttter:


$ flutter packages get

或者,您的编辑可能会支持flutter packages get。查看编辑的文档以了解更多信息。

3.导入它

现在在您的Dart代码中,您可以使用:


import 'package:sqflite/sqflite.dart';
  
版本更新时间文档下载地址
1.1.1Feb 20, 2019Go to the documentation of sqflite 1.1.1Download sqflite 1.1.1 archive
1.1.0+1Feb 19, 2019Go to the documentation of sqflite 1.1.0+1Download sqflite 1.1.0+1 archive
1.1.0Feb 3, 2019Go to the documentation of sqflite 1.1.0Download sqflite 1.1.0 archive
1.0.0Jan 8, 2019Go to the documentation of sqflite 1.0.0Download sqflite 1.0.0 archive
0.13.0+1Dec 21, 2018Go to the documentation of sqflite 0.13.0+1Download sqflite 0.13.0+1 archive
0.13.0Dec 5, 2018Go to the documentation of sqflite 0.13.0Download sqflite 0.13.0 archive
0.12.2+1Oct 11, 2018Go to the documentation of sqflite 0.12.2+1Download sqflite 0.12.2+1 archive
0.12.2Oct 11, 2018Go to the documentation of sqflite 0.12.2Download sqflite 0.12.2 archive
0.12.1Sep 20, 2018Go to the documentation of sqflite 0.12.1Download sqflite 0.12.1 archive
0.12.0Sep 14, 2018Go to the documentation of sqflite 0.12.0Download sqflite 0.12.0 archive

 

 

 

本文来自Pub Package ,经授权后发布,本文观点不代表Flutters立场,转载请联系原作者。

发表评论

登录后才能评论

联系我们

760409815

在线咨询:点击这里给我发消息

邮件:admin@flutters.cn

工作时间:周一至周五,9:30-18:30,节假日休息