Flutter(二十八)——SQLite數據庫

雖有智慧,不如乘勢;雖有鎡基,不如待時。

前言

做過手機端應用開發的人,都應該知道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的基本操作,除了增刪改查稍微複雜一點之外,其他的基本一眼就能掌握,所以本篇終點在於增刪改查。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章