Flutter开发笔记 —— sqflite插件数据库应用

前言

今天在观阅掘金大佬文章的时候,了解到了该 sqflite 插件,结合官网教程和自己实践,由此总结出该文,希望对大家的学习有帮助!

插件详情

Flutter的 SQLite 插件。支持 iOS、Android 和 MacOS。

  • 支持事务和batch模式
  • 打开时自动进行版本管理
  • 插入/查询/更新/删除查询的助手
  • iOS 和 Android 上的数据库操作在后台线程中执行

插件地址: https://pub.dev/packages/sqflite

本文使用插件版本为最新版本:2.3.0

基础介绍

数据表创建

  • openDatabase() 连接数据库
  • deleteDatabase() 删除数据库

openDataBase方法 可选参为db文件地址、版本号、相关回调

案例速览

dart 复制代码
late Database db;
final database = "book.db";
final table = "book";

/*
 * @author Marinda
 * @date 2023/12/13 15:53
 * @description 连接数据库
 */
connection() async{
  //获取
  var databasePath = await getDatabasesPath();
  String path = p.join(databasePath,database);
  //删除数据库
  await deleteDatabase(path);
  print('当前地址:${path}');
  if(File(path).existsSync()){
    db = await openDatabase(path);
  }else{
    db = await openDatabase(path,version: 1,onCreate: (database,version) async{
      database.execute("CREATE TABLE `${table}` (id integer primary key autoincrement,name text not null,price REAL ,author TEXT NOT NULL,description TEXT)");
    });
  }
}

语句介绍

CURD方法介绍

  • 使用SQL语句的CURD前缀带raw (例如rawInsert)
  • 官方封装好的CURD语句不带raw(例如insert) ->全文使用该方法

语法速览

dart 复制代码
//前者
Future<int> rawInsert(String sql, [List<Object?>? arguments]);
//后者
Future<int> insert(String table, Map<String, Object?> values,
    {String? nullColumnHack, ConflictAlgorithm? conflictAlgorithm});

接下来看几个简单的CURD快速了解写法

insert(插入)

dart 复制代码
Future<int> insert() async{
  Map<String,dynamic> args = {
      "id": 1,
      "name": "张飞",
      "description": "猛将"
  };
  //返回id table为表名
  return await db.insert(table,args);
}

delete(删除)

dart 复制代码
Future<int> delete(int id) async{
  return await db.delete(table,where: "id = ?",whereArgs: [id]);
}

update(修改)

dart 复制代码
Future<int> update() async{
  Map<String,dynamic> args = {
      "id": 1,
      "name": "吕布",
      "description": "天下无双"
  };
  return await db.update(table, args,where: "id = ?",whereArgs: [args["id"]]);
}

select(查询)

dart 复制代码
/*
 * @author Marinda
 * @date 2023/12/13 16:11
 * @description 通过id查询
 */
Future<Map<String,dynamic>?> selectById(int id) async{
  var list = await db.query(table,where: "id = ?",whereArgs: [id]);
  if(list.isNotEmpty){
    return list.first;
  }
  return null;
}

现在我们对sqflite插件的基础使用有一个初步的了解了,接下来围绕一个书本表案例做实战

实战应用

  • 定义Book书表作为实体类
  • 定义DBBookProvider类处理数据库表

book.dart

dart 复制代码
/**
 * @author Marinda
 * @date 2023/12/13 15:42
 * @description 书籍信息
 */
class Book {
  int? _id;
  String? _name;
  double? _price;
  String? _author;
  String? _description;

  Book(
      {int? id,
        String? name,
        double? price,
        String? author,
        String? description}) {
    if (id != null) {
      this._id = id;
    }
    if (name != null) {
      this._name = name;
    }
    if (price != null) {
      this._price = price;
    }
    if (author != null) {
      this._author = author;
    }
    if (description != null) {
      this._description = description;
    }
  }

  int? get id => _id;
  set id(int? id) => _id = id;
  String? get name => _name;
  set name(String? name) => _name = name;
  double? get price => _price;
  set price(double? price) => _price = price;
  String? get author => _author;
  set author(String? author) => _author = author;
  String? get description => _description;
  set description(String? description) => _description = description;

  Book.fromJson(Map<String, dynamic> json) {
    _id = json['id'];
    _name = json['name'];
    _price = json['price'];
    _author = json['author'];
    _description = json['description'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['id'] = this._id;
    data['name'] = this._name;
    data['price'] = this._price;
    data['author'] = this._author;
    data['description'] = this._description;
    return data;
  }
}

db_book_provider.dart

dart 复制代码
/**
 * @author Marinda
 * @date 2023/12/13 15:43
 * @description 书籍数据库适配器
 */

class DBBookProvider{
  late Database db;
  final database = "book.db";
  final table = "book";
  static DBBookProvider? _instance;
  static DBBookProvider instance = getInstance();
  DBBookProvider._();

  factory DBBookProvider(){
    return instance;
  }

  static getInstance(){
    if(_instance == null){
      _instance = DBBookProvider._();
    }
    return _instance ?? DBBookProvider._();
  }

  /*
   * @author Marinda
   * @date 2023/12/13 15:53
   * @description 连接数据库
   */
  connection() async{
    var databasePath = await getDatabasesPath();
    String path = p.join(databasePath,database);
    // await deleteDatabase(path);
    print('当前地址:${path}');
    if(File(path).existsSync()){
      db = await openDatabase(path);
    }else{
      db = await openDatabase(path,version: 1,onCreate: (database,version) async{
        database.execute("CREATE TABLE `${table}` (id integer primary key autoincrement,name text not null,price REAL ,author TEXT NOT NULL,description TEXT)");
      });
    }
  }


  /*
   * @author Marinda
   * @date 2023/12/13 16:01
   * @description 关闭数据库
   */
  close() async{
    await db.close();
  }

  /*
   * @author Marinda
   * @date 2023/12/13 16:02
   * @description 插入
   */
  Future<Book> insert(Book book) async{
    int id = await db.insert(table,book.toJson());
    book.id = id;
    return book;
  }

  /*
   * @author Marinda
   * @date 2023/12/13 16:08
   * @description 删除id
   */
  Future<int> delete(int id) async{
    return await db.delete(table,where: "id = ?",whereArgs: [id]);
  }

  /*
   * @author Marinda
   * @date 2023/12/13 16:11
   * @description 通过id查询
   */
  Future<Book?> selectById(int id) async{
    var list = await db.query(table,where: "id = ?",whereArgs: [id]);
    if(list.isNotEmpty){
      return Book.fromJson(list.first);
    }
    return null;
  }

  /*
   * @author Marinda
   * @date 2023/12/13 16:13
   * @description 获取所有书籍列表
   */
  Future<List<Book>> queryList() async{s
    var result = await db.query(table);
    return result.map((e) => Book.fromJson(e)).toList();
  }

  /*
   * @author Marinda
   * @date 2023/12/13 16:15
   * @description 修改书籍信息
   */
  Future<int> update(Book book) async{
    return await db.update(table, book.toJson(),where: "id = ?",whereArgs: [book.id]);
  }

}

实例化调用

dart 复制代码
initDatabase() async{
  DBBookProvider dbBookProvider = DBBookProvider.instance;
  //连接
  await dbBookProvider.connection();
  Book book = Book(
    name: "斗破苍穹",
    author: "天蚕土豆",
    price: 88.00,
    description: "一本不错的小说"
  );
  //插入
  Book element = await dbBookProvider.insert(book);
  print('element : ${element.toJson()}');
  //删除
  for(var id in result){
    await dbBookProvider.delete(id);
  }
 
  Book newBook = Book.fromJson(book.toJson());
  newBook.id = 1;
  newBook.author = "天蚕土豆";
   //修改
  await dbBookProvider.update(newBook);
  //查询全部
  var list = await dbBookProvider.queryList();
  print("当前列表: ${list.map((e) => e.toJson()).toList()}");
}

事务&batch

单独拉出来讲讲的原因是我在应用中踩了个坑

事务和batch是什么这个大家如果不了解的话自行百度一下,下文带大家简单看看案例

dart 复制代码
/*
 * @author Marinda
 * @date 2023/12/13 16:17
 * @description 批量插入全部书籍列表
 */
insertAll(List<Book> bookList) async{
  List resultList = [];
  await db.transaction((txn) async{
    Batch batch = txn.batch();
    for(var book in bookList){
      batch.insert(table,book.toJson());
    }
    //返回全部结果并且不跳过错误!
    resultList = await batch.commit(noResult: false,continueOnError: false);
    print('resultList: ${resultList}');
  });
  await close();
  return resultList;
}

注:在该案例中配合事务 batch.commit方法中如果continueOnError为false时 出现异常则会中止,导致前面插入回推。
注:在该insertAll()方法 或其他涉及事务的方法,都要执行完毕后主动调用close() 断开本次连接。否则会导致 Error Domain=FMDatabase Code=5 "database is locked"

如果已经出现 Error Domain=FMDatabase Code=5 "database is locked" 错误,请删除该数据库文件,重新生成。

结束语

感谢你的观看,希望对大家学习有帮助,有不对的地方欢迎指正!

相关推荐
yatingliu201926 分钟前
HiveQL | 个人学习笔记
hive·笔记·sql·学习
郭庆汝27 分钟前
CMake概述用法详细笔记
笔记
张人玉29 分钟前
XML 序列化与操作详解笔记
xml·前端·笔记
风和日丽 随波逐流30 分钟前
java17学习笔记-Deprecate the Applet API for Removal
笔记·学习
淮北也生橘121 小时前
Linux的ALSA音频框架学习笔记
linux·笔记·学习
薛晓刚2 小时前
当MySQL的int不够用了
数据库
江上清风山间明月2 小时前
Flutter AlwaysScrollableScrollPhysics详解
flutter·滚动·scrollable·scrollphysics
SelectDB技术团队3 小时前
Apache Doris 在菜鸟的大规模湖仓业务场景落地实践
数据库·数据仓库·数据分析·apache doris·菜鸟技术
星空下的曙光3 小时前
mysql 命令语法操作篇 数据库约束有哪些 怎么使用
数据库·mysql
小楓12013 小时前
MySQL數據庫開發教學(一) 基本架構
数据库·后端·mysql