说明

Flutter原生是没有支持数据库操作的,它使用SQLlit插件来使应用具有使用数据库的能力。其实就是Flutter通过插件来与原生系统沟通,来进行数据库操作。

平台支持

  • FLutter的SQLite插件支持IOS,安卓,和MacOS平台
  • 如果要对Linux / Windows / DartVM进行支持请使用sqflite_common_ffi
  • 不支持web平台
  • 数据库操作在安卓或ios的后台执行

使用案例

notepad_sqflite 可以在iOS / Android / Windows / linux / Mac上运行的简单的记事本应用

简单使用

添加依赖

为了使用 SQLite 数据库,首先需要导入 sqflite 和 path 这两个 package

  • sqflite 提供了丰富的类和方法,以便你能便捷实用 SQLite 数据库。
  • path 提供了大量方法,以便你能正确的定义数据库在磁盘上的存储位置。
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();

执行原始的SQL查询

使用getDatabasesPath()获取数据库位置

使用 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 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);

查询表中存储数据的总条数

count = Sqflite.firstIntValue(await database.rawQuery('SELECT COUNT(*) FROM Test'));

关闭数据库

await database.close();

删除数据库

await deleteDatabase(path);

使用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,以供外部使用
  Map<String, Object?> toMap() {
    var map = <String, Object?>{
      columnTitle: title,
      columnDone: done == true ? 1 : 0
    };
    if (id != null) {
      map[columnId] = id;
    }
    return map;
  }
  //无参构造
  Todo();
  
  //把map类型的数据转换成当前类对象的构造函数。
  Todo.fromMap(Map<String, Object?> 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(),conflictAlgorithm: ConflictAlgorithm.replace,);
    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, Object?>> records = await db.query('my_table');

获取结果中的第一条数据

Map<String, Object?> mapRead = records.first;

上面查询结果的列表中Map为只读数据,修改此数据会抛出异常

mapRead['my_column'] = 1;
// Crash... `mapRead` is read-only

创建map副本并修改其中的字段

// 根据上面的map创建一个map副本
Map<String, Object?> map = Map<String, Object?>.from(mapRead);
// 在内存中修改此副本中存储的字段值
map['my_column'] = 1;

把查询出来的List< map>类型的数据转换成List< Todo>类型,这样我们就可以痛快的使用啦。

// Convert the List<Map<String, dynamic> into a List<Todo>.
  return List.generate(maps.length, (i) {
    return Todo(
      id: maps[i][columnId],
      title: maps[i][columnTitle],
      done: maps[i][columnDown],
    );
  });

批处理

您可以使用批处理来避免dart与原生之间频繁的交互。

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"

支持的存储类型

  • 由于尚未对值进行有效性检查,因此请避免使用不受支持的类型。参见:
  • 不支持DateTime类型,可将它存储为int或String
  • 不支持bool类型,可存储为int类型 0:false,1:true

SQLite类型 dart类型 值范围
integer int 从-2 ^ 63到2 ^ 63-1
real num
text String
blob Uint8List

参考

sqflile官方地址
flutter对使用SQLite进行数据存储官方介绍文档

到此这篇关于Flutter数据库的使用方法的文章就介绍到这了,更多相关Flutter数据库使用内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax! 

Flutter数据库的使用方法的更多相关文章

  1. 详解前端HTML5几种存储方式的总结

    本篇文章主要介绍了前端HTML5几种存储方式的总结 ,主要包括本地存储localstorage,本地存储sessionstorage,离线缓存(application cache),Web SQL,IndexedDB。有兴趣的可以了解一下。

  2. PhoneGap / iOS上的SQLite数据库 – 超过5mb可能

    我误解了什么吗?Phonegap中的sqlitedbs真的有5mb的限制吗?我正在使用Phonegap1.2和iOS5.解决方法您可以使用带有phonegap插件的原生sqliteDB,您将没有任何限制.在iOS5.1中,Websql被认为是可以随时删除的临时数据…

  3. ios – 领域:如何获取数据库的当前大小

    是否有RealmAPI方法使用RealmSwift作为数据存储来获取我的RealmSwift应用程序的当前数据库大小?

  4. ios – Realm – 无法使用现有主键值创建对象

    我有一个对象有许多狗的人.应用程序有单独的页面,它只显示狗和其他页面显示人的狗我的模型如下我有人存储在Realm中.人有详细页面,我们取,并显示他的狗.如果狗已经存在,我会更新该狗的最新信息并将其添加到人的狗列表中,否则创建新狗,保存并将其添加到人员列表中.这适用于coredata.在尝试用他的狗更新人时,领域会抛出异常无法使用现有主键值创建对象解决方法这里的问题是,即使你正在创建一个全新的Rea

  5. ios – UIWebView中的WebSQL / SQLite数据库的最大大小(phonegap)

    我知道一般来说,Web应用程序的本地存储空间有5MB的限制.本地网页浏览应用程式是否也有这个限制?

  6. ios – Firebase离线存储高级 – 手动同步和进度信息

    >我可以提供一个捆绑数据库–安装App后我可以已经离线查询了Firebase数据?然后我有另一个关于Firebase的主要问题:>JSON存储是伟大的–但是这样我们不关心一个独特的结构,我们必须注意这一点插入总是正确的数据集?我从来没有试图显示实际的进展,但是当您从firebase中检索数据时,始终会在成功检索数据时调用onDataChange方法.https://firebase.google.com/docs/database/android/retrieve-data#read_data_onceC

  7. ios – 如何处理多用户数据库

    我的应用程序就像很多应用程序–它有一个用户输入用户名和密码的登录屏幕,以及登录按钮我的应用程序还使用CoreData来保存大多数用户的业务对象,当然也是用户特定的.我也有一个登出按钮来启用切换用户.这不会发生很多,但仍然是必要的).现在如果不同的用户登录,我需要获取他的具体数据.但是我该如何做呢?

  8. ios – Swift从Firebase数据库中获取特定价值

    我正在尝试从Firebase数据库中获取特定值.我看了一些像谷歌这样的文件,但我做不到.这是数据库的JSON文件:SWIFT代码:我想获得用户的电子邮件价值,而不是每个人.我怎样才能做到这一点?解决方法在您的代码中,快照将包含子值的字典.要访问它们,请将snapshot.value转换为Dictionary,然后访问各个子项是一个快照

  9. ios – Realm Swift:在卸载应用程序后是否可以保留数据库?

    使用realmswift,即使从设备上卸载应用程序,是否可以在设备内存中保留和维护应用程序的领域数据库文件?非常感谢您的帮助.解决方法删除应用程序时,应用程序的所有文件都是剩余的.iOS应用程序是沙盒.这意味着每个应用程序在磁盘中都有自己的空间,并有自己的目录,这些目录充当应用程序及其数据的主页.从iPhone删除应用程序会删除此沙箱,删除与该应用程序关联的所有数据.

  10. ios – 在没有XML的情况下更新sqlite数据库

    我的应用程序需要来自sqlite数据库的数据.它将附带此数据库的一个版本,但我需要定期更新它(很可能每月一次).通常情况下,我一直在通过我设置的一堆网络服务将我的应用程序的其他部分的更新作为XML发送,但我现在正在处理的这个特定数据库非常大(大约20-30MB),而且我当我尝试以这种方式发送时出现超时错误.我尝试将数据库放在我的公司服务器上,然后将其下载到NSData对象中.然后我将该数据对象保存

随机推荐

  1. Flutter 网络请求框架封装详解

    这篇文章主要介绍了Flutter 网络请求框架封装详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. Android单选按钮RadioButton的使用详解

    今天小编就为大家分享一篇关于Android单选按钮RadioButton的使用详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

  3. 解决android studio 打包发现generate signed apk 消失不见问题

    这篇文章主要介绍了解决android studio 打包发现generate signed apk 消失不见问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

  4. Android 实现自定义圆形listview功能的实例代码

    这篇文章主要介绍了Android 实现自定义圆形listview功能的实例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. 详解Android studio 动态fragment的用法

    这篇文章主要介绍了Android studio 动态fragment的用法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  6. Android用RecyclerView实现图标拖拽排序以及增删管理

    这篇文章主要介绍了Android用RecyclerView实现图标拖拽排序以及增删管理的方法,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下

  7. Android notifyDataSetChanged() 动态更新ListView案例详解

    这篇文章主要介绍了Android notifyDataSetChanged() 动态更新ListView案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下

  8. Android自定义View实现弹幕效果

    这篇文章主要为大家详细介绍了Android自定义View实现弹幕效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  9. Android自定义View实现跟随手指移动

    这篇文章主要为大家详细介绍了Android自定义View实现跟随手指移动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. Android实现多点触摸操作

    这篇文章主要介绍了Android实现多点触摸操作,实现图片的放大、缩小和旋转等处理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部