flutter項目里需要存儲數(shù)據(jù)如果比較少可以用SharedPreferences,
如果存儲數(shù)據(jù)比較多 尤其需要篩選的話 我們就得用數(shù)據(jù)庫了
sqflite
sqflite 是一個 Flutter 插件,用于在 Flutter 應(yīng)用中訪問和操作 SQLite 數(shù)據(jù)庫。它提供了一系列方法來執(zhí)行 SQL 查詢、更新數(shù)據(jù)、以及管理數(shù)據(jù)庫的創(chuàng)建和版本。以下是使用 sqflite 的基本步驟:
打開數(shù)據(jù)庫
創(chuàng)建一個函數(shù)來打開數(shù)據(jù)庫,如果數(shù)據(jù)庫不存在,則創(chuàng)建它。
Future<Database> openDatabase() async {
final databasePath = await getDatabasesPath();
final path = join(databasePath, 'my_database.db');
return openDatabase(
path,
onCreate: (db, version) {
return db.execute(
"CREATE TABLE users(id INTEGER PRIMARY KEY, name TEXT, age INTEGER)",
);
},
version: 1,
);
}
插入數(shù)據(jù)
使用 insert 方法向數(shù)據(jù)庫中插入數(shù)據(jù)。
Future<void> insertUser(Database db, User user) async {
await db.insert(
'users',
user.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
查詢數(shù)據(jù)
使用 query 方法從數(shù)據(jù)庫中查詢數(shù)據(jù)。
Future<List<User>> users(Database db) async {
final List<Map<String, dynamic>> maps = await db.query('users');
return List.generate(maps.length, (i) {
return User(
id: maps[i]['id'],
name: maps[i]['name'],
age: maps[i]['age'],
);
});
}
更新數(shù)據(jù)
使用 update 方法更新數(shù)據(jù)庫中的數(shù)據(jù)。
Future<void> updateUser(Database db, User user) async {
await db.update(
'users',
user.toMap(),
where: "id = ?",
whereArgs: [user.id],
);
}
刪除數(shù)據(jù)
使用 delete 方法從數(shù)據(jù)庫中刪除數(shù)據(jù)。
Future<void> deleteUser(Database db, int id) async {
await db.delete(
'users',
where: "id = ?",
whereArgs: [id],
);
}
關(guān)閉數(shù)據(jù)庫
在適當(dāng)?shù)臅r候關(guān)閉數(shù)據(jù)庫。
await db.close();
注意事項
- 數(shù)據(jù)模型 :考慮創(chuàng)建一個類來表示數(shù)據(jù)庫中的數(shù)據(jù)模型,這將使代碼更加清晰易懂。
- 錯誤處理 :在進行數(shù)據(jù)庫操作時,務(wù)必處理可能出現(xiàn)的錯誤。
-
異步操作 :數(shù)據(jù)庫操作通常是異步的,確保使用
async和await。 - 資源管理 :適當(dāng)時關(guān)閉數(shù)據(jù)庫,避免資源泄漏。
通過使用 sqflite,你可以在 Flutter 應(yīng)用中方便地實現(xiàn)本地數(shù)據(jù)存儲和管理。
數(shù)據(jù)庫升級
在使用 sqflite 管理數(shù)據(jù)庫時,隨著應(yīng)用的發(fā)展,你可能需要更改數(shù)據(jù)庫的結(jié)構(gòu),例如添加新的表或更改現(xiàn)有表的列。這通常涉及到數(shù)據(jù)庫的升級。在 sqflite 中,你可以通過定義不同的數(shù)據(jù)庫版本和升級邏輯來處理這些變化。
步驟
- 增加數(shù)據(jù)庫版本號 :在打開數(shù)據(jù)庫時,將版本號增加到新的版本。
-
處理升級邏輯 :在
openDatabase方法中,使用onUpgrade參數(shù)來定義數(shù)據(jù)庫升級時的行為。
示例
假設(shè)你想在現(xiàn)有的數(shù)據(jù)庫中添加一個新表 orders。
final int newVersion = 2; // 假設(shè)當(dāng)前版本是 2
Database db = await openDatabase(
path,
version: newVersion,
onUpgrade: (Database db, int oldVersion, int newVersion) async {
if (oldVersion < 2) {
// 從版本 1 升級到版本 2
await db.execute("CREATE TABLE orders(id INTEGER PRIMARY KEY, amount INTEGER)");
}
},
// 也可以添加 onDowngrade 來處理降級邏輯
);
注意事項
- 逐步升級 :如果有多個版本,確保從每個舊版本到新版本的升級邏輯都被正確處理。
- 備份數(shù)據(jù) :在進行結(jié)構(gòu)性更改之前,考慮備份重要數(shù)據(jù)。
- 測試升級邏輯 :在發(fā)布新版本之前,確保測試數(shù)據(jù)庫升級邏輯,以避免數(shù)據(jù)丟失或損壞。
- 版本控制 :合理管理數(shù)據(jù)庫版本,確保與應(yīng)用版本的兼容性。
- 錯誤處理 :在執(zhí)行升級腳本時,確保妥善處理可能出現(xiàn)的錯誤。
通過在 sqflite 中管理數(shù)據(jù)庫版本和升級邏輯,你可以確保應(yīng)用的數(shù)據(jù)結(jié)構(gòu)隨著應(yīng)用的發(fā)展而順利演進。
我封裝了sqflite,存一個model 取出來也是一個model
需要查詢的屬性需要自己設(shè)置一個獨立屬性 ,其它屬性放到一個jsonString里面就行
首先建立一個model id是主鍵 默認(rèn)自增,也可以用項目里數(shù)據(jù)屬性的一個id代替,就不用自增了.
class NoteModel {
//唯一di 如果需要查詢屬性比較多,這里都增加上,并在創(chuàng)建table地方增加屬性
//db.execute( 'create table if not exists $tableName
// (id integer primary key autoincrement, content text)');
int? id;
// 可以存 jsonString,使用時候 轉(zhuǎn)成model
String? content;
NoteModel({this.id, this.content});
///提供fromJson以方便將數(shù)據(jù)庫查詢結(jié)果,轉(zhuǎn)成Dart Model
NoteModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
content = json['content'];
}
///提供toJson以方便在持久化數(shù)據(jù)的時候使用
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['content'] = content;
return data;
}
}
下面是使用方法
//數(shù)據(jù)庫名字
String dbName = 'test';
//表名
String tableName = 'tableName1';
Database? database;
JDTableTool? tableTool;
//初始化
void _doInit() async {
// 每次TestDbContentModel結(jié)構(gòu)變化 version +1
Database? db = storage.dateBaseMap[dbName];
if (db != null) {
database = db!;
} else {
database =
await openDatabase(dbName, version: 1, onCreate: (db, version) {
// 在數(shù)據(jù)庫首次創(chuàng)建時執(zhí)行的操作
}, onUpgrade: (db, oldVersion, newVersion) async {
// 在數(shù)據(jù)庫升級時執(zhí)行的操作
if (oldVersion == 1 && newVersion == 2) {
// 如果當(dāng)前數(shù)據(jù)庫版本為1,目標(biāo)版本為2,執(zhí)行操作
}
});
}
jdLog('database?.getVersion: ${await database?.getVersion()}');
if (database != null) {
// name TEXT, value INTEGER, num REAL; 需要查詢的屬性 必須單獨寫成屬性,如果你的map里面有唯一id 就不必要自增了
tableTool = JDStorageTool(database!, tableName,
'create table if not exists $tableName (id integer primary key autoincrement, content text)');
_loadAll();
_loadAll();
}
}
void destroy() {
tableTool?.destroy();
}
///增加數(shù)據(jù)
void _doSave(String nameValue, int age) {
TestDbContentModel contentModel =
TestDbContentModel.fromJson({'name': nameValue, 'age': age});
tableTool?.saveNote(NoteModel(content: jsonEncode(contentModel.toJson())));
_loadAll();
}
///查詢數(shù)據(jù)
void _loadAll() async {
var list = await tableTool?.getAllNote() ?? [];
jdLog('list.length-- ${list.length}');
setState(() {
noteList = list;
});
_getCount();
}
///更新數(shù)據(jù)
void _updateContent() {
if (id == null || name == null) return;
TestDbContentModel contentModel =
TestDbContentModel.fromJson({'name': name, 'age': age});
var model = NoteModel(id: id, content: jsonEncode(contentModel.toJson()));
tableTool?.update(model);
_loadAll();
}
///刪除數(shù)據(jù)
void _doDelete(NoteModel model) {
tableTool?.deleteNote(model.id!);
_loadAll();
}
///查詢列數(shù)
void _getCount() async {
var count = await tableTool?.getNoteCount() ?? 0;
setState(() {
this.count = count;
});
}
具體的封裝實現(xiàn)在https://gitee.com/kuaipai/my_app.git