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 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 insert(
String table, //表名
Map values,//插入的数据
{String? nullColumnHack,
ConflictAlgorithm? conflictAlgorithm
}
);
//插入数据
Futureinsert(Task task)async{
Database db=await database;
print("insert function called");
print("插入的数据:${task.toJson()}");
/*insert方法会返回最后的行id*/
return await db.insert(_ALLTask, task.toJson());
}
Future rawInsert(String sql, [List
//插入数据——法二 rawInsert
Future 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 delete(String table, {String? where, List
Future delete(Task task)async{
Database db=await database;
print("delete function called!");
await db.delete(_ALLTask,where: "id=?",whereArgs: [task.id]);
}
Future update(String table, Map values,
{String? where,
List
//修改任务内容(全部数据)
Future update(Task task)async{
Database db=await database;
return db.update(_ALLTask, task.toJson(), where: 'id=?', whereArgs: [task.id]);
}
Future rawUpdate(String sql, [List
Future rawUpdate(Task task,newDate) async{
Database db=await database;
return db.rawUpdate(
'''
UPDATE $_ALLTask
SET createTime=?
WHERE id=?
''',
[newDate,task.id]
);
Future>> query(String table,
{bool? distinct,
List? columns,
String? where,
List
//查询数据
/*查询到后返回的是一个List
Future>> rawQuery(
String sql,
[List
Future> rawquery() async{
Database db=await database;
print("query function called!");
var result=await db.rawQuery("SELECT * FROM $_ALLTask ");
/*此时返回的是一个List类型*/
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 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]);
}