赞
踩
sqflite
是Flutter
的SQLite
插件,支持的平台有:iOS、Android、MacOS,桌面端可以使用sqflite_common_ffi,本篇文章以sqflite_common_ffi为主。
sqflite_common_ffi定义了一个全局databaseFactoryFfi
允许在 Flutter 和 DartVM 上支持 Linux 和 Windows。所以databaseFactory = databaseFactoryFFi
就可以带来Linux和Windows的支持。databaseFactory
提供了一个直接的 API(openDatabase、deleteDatabase)。
任务要求:构建一个桌面端的任务管理软件,使用sqflite_common_ffi插件。
1、在你的pubspec.yaml文件中添加以下依赖:
2、封装一个数据库操作类 DBHelper()
- class DBHelper {
-
-
- //定义了一个静态变量---_dbHelper,保存DBHelper类的单例实例
- static DBHelper? _dbHelper;
-
- //定义了一个静态方法---getInstance()获取DBHelper的单例实例
- //如果_dbHelper为空,就创建一个新的DBHelper实例
- static DBHelper getInstance() {
- if (_dbHelper == null) {
- _dbHelper = DBHelper();
- }
- return _dbHelper!;
- }
-
- //_db是一个Database类型的成员,用于存储数据库实例
- Database? _db;
-
- //数据库中的表
- static final String _ALLTask = "_ALLTask"; //所有任务
-
- //database是一个异步getter,它返回数据库实例。如果_db为空,就调用initDB方法初始化数据库。
- Future<Database> get database async {
- if (_db != null) {
- return _db!;
- }
- _db = await initDB();
- return _db!;
- }
-
- }
3、初始化数据库操作 initDB()
a.初始化数据库sqfliteFfiInit();
b.获取databaseFactoryFfi对象
c.使用databaseFactoryFfi 对象来打开数据库,语句:databaseFactory.openDatabase()
String Path.(获取数据库的默认位置,最好使用"path_provider"策略)
path_provider的使用:
1、添加依赖
2、在需要的文件中导入包
import 'package:path/path.dart' as path;
openDatabaseOptions(打开数据库操作)的某些属性:
- /// Specify the expected version.
- int? version;
-
- /// called right after opening the database.(打开数据库后立即调用)
- OnDatabaseConfigureFn? onConfigure;
-
- /// Called when the database is created.(数据库创建时的回调函数)
- OnDatabaseCreateFn? onCreate;
-
- /// Called when the database is upgraded.(数据库升级时调用)
- OnDatabaseVersionChangeFn? onUpgrade;
-
- /// Called when the database is downgraded.(数据库降级时调用)
- ///
- /// Use [onDatabaseDowngradeDelete] for re-creating the database
- (使用 [onDatabaseDowngradeDelete] 重新创建数据库)
- OnDatabaseVersionChangeFn? onDowngrade;
-
- /// Called after all other callbacks have been called.(在调用所有其他回调后调用)
- OnDatabaseOpenFn? onOpen;
-
- /// Open the database in read-only mode (no callback called).(以只读模式打开数据库(不调用回调)。)
- late bool readOnly;
-
- /// The existing single-instance (hot-restart)(现有单实例(热重启))
- late bool singleInstance;
- //初始化数据库
- initDB()async{
- //1、初始化数据库
- sqfliteFfiInit();
-
- //2、获取databaseFactoryFfi对象
- var databaseFactory = databaseFactoryFfi;
-
- //3、创建数据库
- return await databaseFactory.openDatabase(
-
- //数据库路径
- path.join(await databaseFactory.getDatabasesPath(), "TO-DO.db"),
-
- //打开数据库操作
- options: OpenDatabaseOptions(
- //版本
- version: 5,
- //创建时操作
- onCreate: (db,version)async{
- print("创建数据库");
- return await db.execute(
- "CREATE TABLE $_ALLTask ("
- "id INTEGER PRIMARY KEY AUTOINCREMENT,"
- "content TEXT,"
- "ownType STRING,"
- "startDate STRING,"
- "endDate STRING,"
- "createTime STRING,"
- "completeTime STRING,"
- "repeat STRING,"
- "isCompleted INTEGER"
- ")"
- );
- }
- )
- );
- }
至此,数据库创建完成。
- Future<int> insert(
- String table, //表名
- Map<String, Object?> values,//插入的数据
- {String? nullColumnHack,
- ConflictAlgorithm? conflictAlgorithm
- }
- );
- //插入数据
- Future<int>insert(Task task)async{
- Database db=await database;
- print("insert function called");
- print("插入的数据:${task.toJson()}");
- /*insert方法会返回最后的行id*/
- return await db.insert(_ALLTask, task.toJson());
- }
Future<int> rawInsert(String sql, [List<Object?>? arguments]);
- //插入数据——法二 rawInsert
- Future<int> rawInsert(Task task) async{
-
- Database db=await database;
-
- return await db.rawInsert(
- "INSERT INTO $_ALLTask (content, ownType, startDate, endDate, createTime,
- completeTime, repeat, isCompleted) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",[task.content,task.ownType,task.startDate,task.endDate,task.createTime,task.completeTime,task.repeat,task.isCompleted]);
- }
使用 whereArgs 将参数传递给 where 语句。有助于防止 SQL 注入攻击
Future<int> delete(String table, {String? where, List<Object?>? whereArgs});
- Future delete(Task task)async{
- Database db=await database;
- print("delete function called!");
- await db.delete(_ALLTask,where: "id=?",whereArgs: [task.id]);
- }
- Future<int> update(String table, Map<String, Object?> values,
- {String? where,
- List<Object?>? whereArgs,
- ConflictAlgorithm? conflictAlgorithm});
- //修改任务内容(全部数据)
- Future update(Task task)async{
-
- Database db=await database;
- return db.update(_ALLTask, task.toJson(), where: 'id=?', whereArgs: [task.id]);
- }
Future<int> rawUpdate(String sql, [List<Object?>? arguments]);
- Future rawUpdate(Task task,newDate) async{
-
- Database db=await database;
- return db.rawUpdate(
- '''
- UPDATE $_ALLTask
- SET createTime=?
- WHERE id=?
- ''',
- [newDate,task.id]
- );
- Future<List<Map<String, Object?>>> query(String table,
- {bool? distinct,
- List<String>? columns,
- String? where,
- List<Object?>? whereArgs,
- String? groupBy,
- String? having,
- String? orderBy,
- int? limit,
- int? offset});
- //查询数据
- /*查询到后返回的是一个List<Map<String,Object?>>类型的列表,每一个元素都是Map<String,Object?>
- *result就是List<Map<String,Object?>>类型的列表
- *result.map((taskMap) => Task.fromJson(taskMap))=======>遍历每一个元素,将每一个元素都执行
- *给定的函数,此处是Task.fromJson(taskMap),然后返回一个新的迭代器
- *所以这个迭代器里的每一个元素都转换成了Task类型
- *.toList();将这个迭代器转换成列表
- * 所以最后就返回了一个Task类型的列表 */
- Future<List<Task>> query() async{
- Database db=await database;
- print("query function called!");
- var result=await db.query(_ALLTask);
- /*此时返回的是一个List<Task>类型*/
- return result.map((taskMap) => Task.fromJson(taskMap)).toList();
-
- }
- Future<List<Map<String, Object?>>> rawQuery(
- String sql,
- [List<Object?>? arguments]);
- Future<List<Task>> rawquery() async{
- Database db=await database;
- print("query function called!");
- var result=await db.rawQuery("SELECT * FROM $_ALLTask ");
- /*此时返回的是一个List<Task>类型*/
- return result.map((taskMap) => Task.fromJson(taskMap)).toList();
-
- }
ASC:表示按升序排序。 DESC:表示按降序排序。
var result=await db.query(_ALLTask,orderBy: "datetime(createTime) ASC");
var result=await db.rawQuery("SELECT * FROM $_ALLTask ORDER BY datetime(createTime) DESC");
此时我想按照字段 createTime进行升序、降序。但是字段createTime是String类型。
SQLite中支持多种日期时间格式,但是建议使用ISO 8601格式来存储日期时间值。ISO 8601是一种国际标准,用于表示日期、时间和日期时间值。它的格式如下:
YYYY-MM-DDTHH:MM:SS.SSSZ
其中,YYYY表示年份,MM表示月份,DD表示日期,T表示时间分隔符,HH表示小时,MM表示分钟,SS表示秒,.SSS表示毫秒(可选),Z表示时区偏移量
我的时间格式如下:2023-07-12--11:23:02
- String timeStr = "2023-07-12--11:23:02";
-
- //首先使用replaceAll()方法将时间字符串中的--替换为T,以便它符合ISO 8601格式
- //使用DateTime.parse()方法将字符串解析为日期时间类型。
- DateTime dateTime = DateTime.parse(timeStr.replaceAll("--", "T"));
-
- //使用toIso8601String()方法将日期时间类型格式化为ISO 8601字符串
- String iso8601Str = dateTime.toIso8601String();
-
- print("${iso8601Str}");
-
最后打印出的数据:2023-07-12T15:26:31.000
- Future<void> addColumn() async {
- Database db = await database;
- await db.execute("ALTER $_ALLTask task ADD COLUMN priority INTEGER DEFAULT 0");
- }
默认值此时为0,如果不设置默认值的话,默认值全部为null
在priority默认值全部为null的时候修改为0:
- //设置新列的默认值
- Future setdefaultValue()async{
- Database db = await database;
- await db.execute("UPDATE $_ALLTask SET priority = ? WHERE priority IS ?",[0,null]);
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。