雖有智慧,不如乘勢;雖有鎡基,不如待時。
前言
做過手機端應用開發的人,都應該知道SQLite數據庫,它是手機端上最老牌,最流行的數據庫。使用起來比shared_preferences稍微複雜一點。
前面一篇博文介紹的shared_preferences,我們可以理解爲key-value的存儲模式,在需要對大量數據進行增刪改查操作時,我們就必須使用數據庫。比如,在新聞App中,爲了用戶更好的體驗,我們需要存儲一些新聞數據,方便用戶在離線的模式下,也能體驗App的基本功能。
所以爲了更好的操作SQLite數據庫,Flutter爲我們提供了sqflite插件進行數據庫的操作,下面我們來詳細講解SQLite的操作方式。
sqflite依賴庫
目前與數據庫相關,並且使用最廣的依賴庫就是sqflite。它同時支持Android和IOS兩個版本。我們可以直接在Flutter Packages上搜索sqflite,找到下載地址和使用說明。sqflite有以下特性:
(1)支持事務和批處理
(2)支持自動Version管理
(3)支持增刪改查的Helpers工具類
(4)支持Android/iOS後臺線程的運行
既然我們之前說過sqflite是插件,所以我們開發的時候,需要在Flutter項目中引入這個插件,代碼如下:
dependencies:
flutter:
sdk: flutter
shared_preferences: ^0.5.1+1
sqflite: ^1.1.3//引入代碼
sqflite基本用法
sqflite常用的操作方式有8種,代碼如下所示:
獲取和刪除database
_getOrdelete_database()async{
var databasesPath=await getDatabasesPath();
String path=join(databasesPath,'demo.db');
await deleteDatabase(path);
}
創建數據庫與數據表
_create_database() async{
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 Demo(id INTEGER PRIMARY KEY,name TEXT,value INTEGER,num REAL)');
});
}
插入數據
第一種插入數據方法的定義,代碼如下:
Future<int> rawInsert(String sql,[List<dynamic> arguments]);
從參數的名稱我們可以看出來,第一個參數是一個字符串的sql語句,第二個參數就是傳遞的List類型的參數,當然前面sql語句需要使用“?”作爲佔位符,才能傳遞第二個參數,具體使用代碼如下:
_insert_database() async{
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 Demo(id INTEGER PRIMARY KEY,name TEXT,age INTEGER)');
});
await database.transaction((txn) async {
int id1 = await txn.rawInsert(
'INSERT INTO Demo(name, value, num) VALUES(?, ?)',['Liyuanjing',27]);
print('inserted1: $id1');
});
}
這種是在直接使用sql語句的情況下插入數據,而且參數必須與前面佔位符個數一致。
第二種方法在直接使用表名進行插入:
Future<int> insert(String table,Map<String,dynamic> values,{String nullColumnHack,ConflictAlgorithm conflictAlgorithm});
這個方法第一個參數是需要操作的表明,第二個參數是需要插入的數據,通過字段名與對應的值匹配插入,使用代碼如下:
_insert_database() async{
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 Demo(id INTEGER PRIMARY KEY,name TEXT,age INTEGER)');
});
Map<String,dynamic> values={
'name':'Liyuanjing',
'age': 27,
};
await database.insert('Demo', values);
}
修改數據
修改操作同樣有兩種操作方式,第一種方法定義的代碼如下:
Future<int> rawUpdate(String sql,[List<dynamic> arguments]);
使用的詳細代碼如下:
_update_table() async{
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 Demo(id INTEGER PRIMARY KEY,name TEXT,age INTEGER)');
});
await database.transaction((txn) async {
int id1 = await txn.rawUpdate(
'UPDATE Demo SET name=? WHERE age=?',["Batman",27]);
print('inserted1: $id1');
});
}
第二種方法的代碼如下:
Future<int> update(String table,Map<String,dynamic> values,{String where,List<dynamic> whereArgs,ConflictAlgorithm conflictAlgorithm})
使用的代碼如下,跟(3)中的第二種方法類似:
_update_table() async{
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 Demo(id INTEGER PRIMARY KEY,name TEXT,age INTEGER)');
});
Map<String,dynamic> values={
'name':'Batman',
};
await database.update('Demo', values,where: 'age=?',whereArgs: [27,]);
}
查詢數據
同樣,查詢在sqflite插件中,也有兩種操作方式,第一種的方法定義如下:
Future<List<Map<String,dynamic>>> rawQuery(String sql,[List<dynamic> arguments]);
rawQuery方法的第一個參數爲查詢用的sql語句,同樣用佔位符代替參數,第二個參數傳入List類型參數來填充sql語句的佔位符,佔位符與List個數一致,使用代碼如下:
_select_database() async{
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 Demo(id INTEGER PRIMARY KEY,name TEXT,age INTEGER)');
});
await database.transaction((txn) async {
List<Map<String,dynamic>> id1 = await txn.rawQuery(
'SELECT * FROM Demo WHERE age=?',[27]);
});
}
接着我們在來看看第二種查詢方法的定義,代碼如下:
Future<List<Map<String,dynamic>>> query(String table,
{bool distinct,
List<String> columns,
String where,
List<dynamic> whereArgs,
String groupBy,
String having,
String orderBy,
int limit,
int offset});
query方法的第一個參數是操作表名,後邊的可選參數依次表示是否去重,查詢字段,where的查詢子句,where子句的佔位符參數值,分組查詢子句(groupBy),having子句,orderBy排序子句,limit查詢上限條數,查詢的偏移位(offset)。基本的使用代碼如下:
_select_database() async{
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 Demo(id INTEGER PRIMARY KEY,name TEXT,age INTEGER)');
});
await database.query('Demo',where: 'age=?',whereArgs: [27,]);
}
刪除數據
刪除數據也分爲兩種分別是物理刪除和邏輯刪除。物理刪除指的是操作真實的數據庫並實現刪除操作,而邏輯刪除指的是通過update語句修改數據庫,並且在查詢時過濾掉不符合查詢條件的記錄,下面我們看一下sqflite裏怎樣實現邏輯刪除。兩種操作方式的方法定義代碼如下:
Future<int> rawDelete(String sql,[List<dynamic arguments>]);
Future<int> delete(String table,{String where,List<dynamic> whereArgs});
這兩種操作方式與上面的增改差基本一致,這裏就不在用代碼贅述了,除了sql語句不同,其他的一摸一樣。
計算總記錄數
我們直接看代碼:
Sqflite.firstIntValue(await database.rawQuery('Select COUNT(*) FROM Demo'));
關閉數據庫
代碼很簡單,我們這裏也直接上代碼:
await database.close();
以上八個操作是sqflite的基本操作,除了增刪改查稍微複雜一點之外,其他的基本一眼就能掌握,所以本篇終點在於增刪改查。