Flutter笔记: 在Flutter应用中使用SQLite数据库

Flutter笔记
在Flutter应用中使用SQLite数据库(基于sqflite)

作者李俊才 (jcLee95):https://blog.csdn.net/qq_28550263
邮箱 :291148484@163.com
本文地址:https://blog.csdn.net/qq_28550263/article/details/134451075

【简介】本文旨在介绍在 Flutter 中通过 sqflite 模块使用 SQLite 数据库。



1. 概述

SQLite是一种轻量级的嵌入式关系型数据库管理系统,而在Flutter中,我们可以通过使用 sqflite 模块方便地进行SQLite数据库的操作。本文将介绍如何在Flutter应用中使用 sqflite 来进行数据库操作。如果你对ORM(对象关系映射)有兴趣,可以参考以下文章:

  • 《在 Floor (ORM框架)中自动生成数据库代码》:https://jclee95.blog.csdn.net/article/details/134356076#4
  • 《用于ORM的Floor框架》:https://jclee95.blog.csdn.net/article/details/133377191
  • 《Dart笔记:一些代码生成工具站点的介绍》:https://jclee95.blog.csdn.net/article/details/134349100

在接下来的内容中,我们将深入了解如何使用 sqflite 在Flutter应用中创建、查询、更新和删除数据库记录,以及如何执行异步操作和处理数据库版本升级。

2. 安装和配置 sqflite

在使用 sqflite 之前,我们需要将其添加为Flutter应用的依赖项,并在代码中导入相应的模块。

2.1 添加依赖

打开你的Flutter应用的 pubspec.yaml 文件,并在 dependencies 部分添加 sqflite 依赖:

dependencies:sqflite: ^2.3.0

这将使用指定版本的 sqflite 库。你可以通过 pub.dev 查看最新版本。

保存 pubspec.yaml 文件后,运行以下命令来获取依赖:

flutter pub get

如果你想直接安装最新版本亦可以通过运行下面的命令:

flutter pub add sqflite

这将在 pubspec.yaml 文件中添加最新版本作为依赖,并隐式的运行一个 flutter pub get 命令。

2.2 导入模块

在你的Dart文件中,导入 sqflite 模块:

import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';// 其他导入...

以上是在Flutter应用中添加和配置 sqflite 的步骤。在接下来的部分,我们将深入研究如何使用 sqflite 进行数据库操作。

3. SQL 基础知识 和 SQLite 工具

3.1 创建表

在SQL中,我们使用CREATE TABLE语句来创建新的表。以下是创建表的示例代码:

CREATE TABLE my_table(id INTEGER PRIMARY KEY,name TEXT
);

在上面的SQL语句中,我们创建了一个名为my_table的表,它有两个字段:id和name。id字段是整数类型,并作为主键,name字段是文本类型。

3.2 插入数据

在上面的SQL语句中,我们使用INSERT INTO语句来插入新的数据。以下是插入数据的示例代码:

INSERT INTO my_table(id, name) VALUES(1, 'Jack');

在上面的SQL语句中,我们向my_table表插入了一条新的数据,id字段的值为1,name字段的值为’Jack’。

3.3 查询数据

在SQL中,我们使用SELECT语句来查询数据。以下是查询所有数据的示例代码:

SELECT * FROM my_table;

在上面的SQL语句中,我们查询了my_table表的所有数据。

3.4 更新数据

在SQL中,我们使用UPDATE语句来更新数据。以下是更新数据的示例代码:

UPDATE my_table SET name = 'Bob' WHERE id = 1;

在上面的SQL语句中,我们更新了my_table表中id字段为1的数据,将name字段的值改为’Bob’。

3.5 删除数据

在SQL中,我们使用DELETE FROM语句来删除数据。以下是删除数据的示例代码:

DELETE FROM my_table WHERE id = 1;

在上面的SQL语句中,我们删除了my_table表中id字段为1的数据。

3.6 数据库工具

SQLiteSpy 工具

SQLiteSpy 是一款免费的快速且紧凑的图形用户界面(GUI)工具,用于管理 SQLite 数据库,你可以自由地下载和使用。它的设计目标是使得 SQLite 数据库的开发和维护变得更加简单和轻松。SQLiteSpy 提供了丰富的功能,包括数据库结构查看、SQL 查询编辑器、数据导入/导出等。它还支持 SQLite 的所有数据类型,包括 BLOB。

下载地址:https://download.csdn.net/download/qq_28550263/88545032

在这里插入图片描述

在 Windows 上调试运行 Flutter 时,数据库文件位置在 项目根目录.dart_tool\sqflite_common_ffi\databases
在这里插入图片描述

Android Studio

可以可以在插件市场搜索一个你喜欢的SQLite插件:
在这里插入图片描述
然后打开 设备文件浏览器
在这里插入图片描述

然后在应用下找到数据库文件。

如果使用 Floor 的话,数据库时自动创建的。假设你的应用的包名是 my_app,那么你的应用的数据库文件应该位于 /data/data/com.example.my_app/databases/ 目录下。
在这里插入图片描述
双击后,数据库插件将在新的标签中打开:

在这里插入图片描述
(此处演示的表是空的,但是可以看到表的各个字段)

4. 创建数据库

4.1 定义数据库路径

首先,我们需要定义数据库文件的路径。在 AndroidiOS 上,我们通常将数据库文件存储在设备的文件系统中。我们可以使用 path_provider 库来获取这些路径。

首先,添加 path_provider 依赖到你的 pubspec.yaml 文件:

dependencies:flutter:sdk: fluttersqflite: anypath_provider: any

然后,导入path_provider和sqflite库,并定义一个函数来获取数据库路径:

import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'dart:io' as io;
import 'package:path/path.dart';// 定义一个异步函数来获取数据库路径
Future<String> getDatabasePath(String dbName) async {// 获取应用的文档目录final directory = await getApplicationDocumentsDirectory();// 拼接路径final path = join(directory.path, dbName);return path;
}

作为对比,以前介绍过 Floor 库。Floor 是一个基于 SQLiteORM 框架,它在底层使用了 sqflite 库。但是,Floor 框架已经封装了数据库路径的获取和数据库的创建,所以在使用 Floor 框架时,你不需要显式地使用 path_provider 库来获取数据库路径。
当你使用 Floor 框架创建数据库时,只需要提供数据库的名称,Floor 框架会自动为你处理数据库路径的问题。例如:

final database = await $FloorAppDatabase.databaseBuilder('app_database.db').build();

4.2 创建数据库表

有了数据库路径,我们就可以创建数据库和表了。我们可以定义一个函数来创建数据库和表:

Future<Database> createDatabase() async {// 获取数据库路径final path = await getDatabasePath('my_db.db');// 打开数据库final database = openDatabase(path,version: 1,// 当数据库第一次被创建时,执行创建表的操作onCreate: (db, version) {return db.execute("CREATE TABLE my_table(id INTEGER PRIMARY KEY, name TEXT)",);},);return database;
}

在上述代码中,我们首先调用openDatabase函数并传入数据库路径。如果数据库文件不存在,openDatabase函数会创建一个新的数据库文件。然后,我们定义了一个onCreate回调函数,当数据库第一次被创建时,这个函数会被调用。在这个函数中,我们执行了一个SQL语句来创建一个新的表my_table。

5. 插入数据

5.1 创建数据模型

在插入数据之前,我们通常会创建一个数据模型来表示我们的数据。以下是一个简单的数据模型示例:

class MyData {final int id;final String name;// 构造函数MyData({required this.id, required this.name});// 将MyData对象转换为MapMap<String, dynamic> toMap() {return {'id': id,'name': name,};}
}

在上述代码中,我们定义了一个MyData类,它有两个字段:id和name。我们还定义了一个toMap方法,它将MyData对象转换为一个Map,这样我们就可以将它插入到数据库中。

5.2 插入数据记录

有了数据模型,我们就可以插入数据到数据库中了。以下是插入数据的示例代码:

Future<void> insertData(MyData data, Database db) async {try {// 插入数据到数据库await db.insert('my_table',data.toMap(),// 如果插入的数据与已有数据冲突(例如,两个数据有相同的主键),则替换旧数据conflictAlgorithm: ConflictAlgorithm.replace,);} catch (e) {// 打印错误信息print('Failed to insert data: $e');}
}

在上述代码中,我们定义了一个insertData函数,它接受一个MyData对象和一个Database对象。我们调用db.insert方法来插入数据。我们传入表名my_table,以及通过data.toMap()得到的Map。如果插入的数据与已有数据冲突(例如,两个数据有相同的主键),我们选择替换旧数据,这是通过设置conflictAlgorithm为ConflictAlgorithm.replace实现的。

6. 查询数据

6.1 执行查询操作

在sqflite中,我们可以使用query方法来执行查询操作。以下是查询所有数据的示例代码:

Future<List<Map<String, dynamic>>> queryAll(Database db) async {// 查询所有数据return await db.query('my_table');
}

在上述代码中,我们定义了一个queryAll函数,它接受一个Database对象,并返回一个包含所有数据的列表。我们调用db.query方法并传入表名my_table来查询所有数据。

6.2 处理查询结果

查询结果是一个Map的列表,每个Map代表一条数据记录。我们可以将这些Map转换为我们的数据模型。以下是处理查询结果的示例代码:

Future<List<MyData>> getMyDataFromDB(Database db) async {// 获取所有数据final List<Map<String, dynamic>> maps = await queryAll(db);// 将Map转换为MyData对象return List.generate(maps.length, (i) {return MyData(id: maps[i]['id'],name: maps[i]['name'],);});
}

在上述代码中,我们定义了一个getMyDataFromDB函数,它接受一个Database对象,并返回一个MyData对象的列表。我们首先调用queryAll函数来获取所有数据,然后使用List.generate方法来生成一个MyData对象的列表。在生成列表的过程中,我们从每个Map中获取id和name字段,并创建一个新的MyData对象。

7. 更新数据

7.1 更新数据记录

在sqflite中,我们可以使用update方法来更新数据。以下是更新数据的示例代码:

Future<void> updateData(MyData data, Database db) async {// 更新数据await db.update('my_table',data.toMap(),// 指定哪些记录应该被更新where: "id = ?",whereArgs: [data.id],);
}

在上述代码中,我们定义了一个updateData函数,它接受一个MyData对象和一个Database对象。我们调用db.update方法来更新数据。我们传入表名my_table,以及通过data.toMap()得到的Map。我们还指定了where和whereArgs参数,以确定哪些记录应该被更新。在这个例子中,我们更新id字段等于data.id的记录。

7.2 验证更新结果

为了验证数据是否已经被更新,我们可以再次查询数据,并检查数据是否符合预期。以下是验证更新结果的示例代码:

Future<void> verifyUpdate(MyData data, Database db) async {// 从数据库中获取所有数据List<MyData> dataList = await getMyDataFromDB(db);// 遍历数据列表for (var item in dataList) {// 如果找到id与待验证数据id相同的数据项if (item.id == data.id) {// 断言其name字段与待验证数据的name字段相同assert(item.name == data.name);}}
}

在上述代码中,我们定义了一个verifyUpdate函数,它接受一个MyData对象和一个Database对象。我们首先调用getMyDataFromDB函数来获取所有数据,然后遍历数据列表,找到id字段等于data.id的记录,并检查其name字段是否等于data.name。如果等于,那么说明更新操作成功。

8. 删除数据

8.1 删除数据记录

在sqflite中,我们可以使用delete方法来删除数据。以下是删除数据的示例代码:

Future<void> deleteData(int id, Database db) async {// 调用delete方法删除指定id的数据await db.delete('my_table',// where子句用于指定要删除的数据where: "id = ?",whereArgs: [id],);
}

在上述代码中,我们定义了一个deleteData函数,它接受一个id和一个Database对象。我们调用db.delete方法来删除数据。我们传入表名my_table,并指定where和whereArgs参数,以确定哪些记录应该被删除。在这个例子中,我们删除id字段等于给定id的记录。

8.2 验证删除结果

为了验证数据是否已经被删除,我们可以再次查询数据,并检查数据是否符合预期。以下是验证删除结果的示例代码:

Future<void> verifyDelete(int id, Database db) async {// 从数据库中获取所有数据List<MyData> dataList = await getMyDataFromDB(db);// 遍历数据列表for (var item in dataList) {// 断言每个数据项的id都不等于已删除的数据idassert(item.id != id);}
}

在上述代码中,我们定义了一个verifyDelete函数,它接受一个id和一个Database对象。我们首先调用getMyDataFromDB函数来获取所有数据,然后遍历数据列表,检查每个记录的id字段是否不等于给定的id。如果所有记录的id字段都不等于给定的id,那么说明删除操作成功。

9. 数据库版本升级

随着应用的发展,我们可能需要修改数据库的结构,例如添加新的表或修改现有的表。这就需要升级数据库版本。在sqflite中,我们可以在打开数据库时指定版本号,并提供一个onUpgrade回调函数来处理数据库升级。

9.1 定义新的数据库版本

以下是定义新的数据库版本的示例代码:

Future<Database> createDatabase() async {// 获取数据库路径final path = await getDatabasePath('my_db.db');// 打开数据库,指定新的版本号final database = openDatabase(path,version: 2, // 新的版本号onCreate: (db, version) {return db.execute("CREATE TABLE my_table(id INTEGER PRIMARY KEY, name TEXT)",);},// 当数据库版本升级时,执行数据库升级操作onUpgrade: (db, oldVersion, newVersion) {// 处理数据库升级...},);return database;
}

在上述代码中,我们在openDatabase函数中指定了新的版本号。我们还提供了一个onUpgrade回调函数,当数据库版本升级时,这个函数会被调用。

9.2 执行数据库升级操作

以下是执行数据库升级操作的示例代码:

Future<Database> createDatabase() async {try {// 获取数据库路径final path = await getDatabasePath('my_db.db');// 打开数据库,指定新的版本号final database = openDatabase(path,version: 2,onCreate: (db, version) {// 创建表return db.execute("CREATE TABLE my_table(id INTEGER PRIMARY KEY, name TEXT)",);},// 当数据库版本升级时,执行数据库升级操作onUpgrade: (db, oldVersion, newVersion) {// 如果旧版本号小于2,为my_table表添加一个新的列ageif (oldVersion < 2) {// 执行SQL语句,修改my_table表,添加新的列agedb.execute("ALTER TABLE my_table ADD COLUMN age INTEGER");}},);// 返回数据库实例return database;} catch (e) {// 打印错误信息print('Failed to open database: $e');// 抛出异常throw e;}
}

在上述代码中,我们在onUpgrade回调函数中执行了一个SQL语句来修改my_table表,添加了一个新的列age。我们只在旧版本号小于2时执行这个操作,这是因为如果用户已经在版本2或更高版本的数据库中,那么age列已经存在,无需再次添加。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/148140.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

物联网AI MicroPython学习之语法 TIMER硬件定时器

学物联网&#xff0c;来万物简单IoT物联网&#xff01;&#xff01; TIMER 介绍 模块功能: 硬件定时器模块 接口说明 Timer - 构建Timer对象 函数原型&#xff1a;Timer(id)参数说明&#xff1a; 参数类型必选参数&#xff1f;说明idintY硬件定时器外设模块id&#xff1a…

【算法每日一练]-分块(保姆级教程 篇1)POJ3648

插讲一下分块 题目&#xff1a;&#xff08;POJ 3648&#xff09; 一个简单的整数问题 前缀和往往用于静态的不会修改的区间和。遇到经常修改的区间问题&#xff0c;就要用分块或线段树来维护了。 分块算法是优化后的暴力&#xff0c;分块算法有时可以维护一些线段树维护不了的…

【ArcGIS Pro二次开发】:CC工具箱1.1.1更新_免费_安装即可用

CC工具箱1.1.1更新【2023.11.15】 使用环境要求&#xff1a;ArcGIS Pro 3.0 一、下载链接 工具安装文件及使用文档&#xff1a; https://pan.baidu.com/s/1OJmO6IPtMfX_vob3bMtvEg?pwduh5rhttps://pan.baidu.com/s/1OJmO6IPtMfX_vob3bMtvEg?pwduh5r 二、使用方法 1、在下…

数据结构与算法-图

图 &#x1f388;2.图的存储结构&#x1f4d6;2.4.2邻接表的存储✅2.4.2.1逆邻接表✅2.4.2.2邻接表存储结构的定义✅2.4.2.3邻接表存储结构的类定义✅2.4.2.4创建n个顶点m条边的无向网✅2.4.2.5创建n个顶点m条边的有向网✅2.4.2.6定位操作-查找定点信息在顶点数组中的下标✅2.4…

【每日一题】689. 三个无重叠子数组的最大和-2023.11.19

题目&#xff1a; 689. 三个无重叠子数组的最大和 给你一个整数数组 nums 和一个整数 k &#xff0c;找出三个长度为 k 、互不重叠、且全部数字和&#xff08;3 * k 项&#xff09;最大的子数组&#xff0c;并返回这三个子数组。 以下标的数组形式返回结果&#xff0c;数组中…

4、FFmpeg命令行操作10

音视频处理流程 先看两条命令 ffmpeg -i test_1920x1080.mp4 -acodec copy -vcodec libx264 -s 1280x720 test_1280x720.flv ffmpeg -i test_1920x1080.mp4 -acodec copy -vcodec libx265 -s 1280x720 test_1280x720.mkv ffmpeg音视频处理流程

拼图小游戏

运行出的游戏界面如下&#xff1a; User类 package domain;/*** ClassName: User* Author: Kox* Data: 2023/2/2* Sketch:*/ public class User {private String username;private String password;public User() {}public User(String username, String password) {this.user…

Flink(七)【输出算子(Sink)】

前言 今天是我写博客的第 200 篇&#xff0c;恍惚间两年过去了&#xff0c;现在已经是大三的学长了。仍然记得两年前第一次写博客的时候&#xff0c;当时学的应该是 Java 语言&#xff0c;菜的一批&#xff0c;写了就删&#xff0c;怕被人看到丢脸。当时就想着自己一年之后&…

Windows上搭建一个网站(基本生产环境)

前言 本博客记录的是Windows上一次网站搭建的过程&#xff0c;主要是在前端采用的是React&#xff0c;后端采用的是Flask&#xff0c;记录一下生产版本搭建流程和坑点&#xff0c;供有缘人一起进步&#xff0c;当然本博客还存在很多不足。 前端项目构建生产版本 以React为例…

Pandas+Matplotlib 数据分析

利用可视化探索图表 一、数据可视化与探索图 数据可视化是指用图形或表格的方式来呈现数据。图表能够清楚地呈现数据性质&#xff0c; 以及数据间或属性间的关系&#xff0c;可以轻易地让人看图释义。用户通过探索图&#xff08;Exploratory Graph&#xff09;可以了解数据的…

实在智能携手中国电信翼支付,全球首款Agent智能体亮相2023数字科技生态大会

11月10日-13日&#xff0c;中国电信与广东省人民政府联合主办的“2023数字科技生态大会”在广州隆重举行。本届大会以“数字科技焕新启航”为主题&#xff0c;邀请众多生态合作伙伴全方位展示数字科技新成果&#xff0c;包括数字新消费、产业数字化、智能电子、人工智能大模型等…

K-Means算法进行分类

已知数据集D中有9个数据点&#xff0c;分别是&#xff08;1,2&#xff09;&#xff0c;(2,3), (2,1), (3,1),(2,4),(3,5),(4,3),(1,5),(4,2)。采用K-Means算法进行聚类&#xff0c;k2&#xff0c;设初始中心点为&#xff08;1.1,2.2&#xff09;&#xff0c;&#xff08;2.3,3.…

OpenAI发布会中不起眼的重大更新

上周&#xff0c;OpenAI的历史首届开发者大会上&#xff0c;OpenAI的首席执行官山姆奥特曼展示了一系列产品更新&#xff0c;包含了众多重磅功能&#xff0c;就算单独拿出来都能让科技圈震一震&#xff0c;一下能发布这么多也真是家底厚。 果不其然&#xff0c;接下来的一周&am…

Java拼图

第一步是创建项目 项目名自拟 第二部创建个包名 来规范class 然后是创建类 创建一个代码类 和一个运行类 代码如下&#xff1a; package heima;import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import jav…

Hive语法,函数--学习笔记

1&#xff0c;排序处理 1.1cluster by排序 &#xff0c;在Hive中使用order by排序时是全表扫描&#xff0c;且仅使用一个Reduce完成。 在海量数据待排序查询处理时&#xff0c;可以采用【先分桶再排序】的策略提升效率。此时&#xff0c; 就可以使用cluster by语法。 cluster…

RocketMQ(三):集成SpringBoot

RocketMQ系列文章 RocketMQ(一)&#xff1a;基本概念和环境搭建 RocketMQ(二)&#xff1a;原生API快速入门 RocketMQ(三)&#xff1a;集成SpringBoot 目录 一、搭建环境二、不同类型消息1、同步消息2、异步消息3、单向消息4、延迟消息5、顺序消息6、带tag消息7、带key消息 一…

Accelerate 0.24.0文档 三:超大模型推理(内存估算、Sharded checkpoints、bitsandbytes量化、分布式推理)

文章目录 一、内存估算1.1 Gradio Demos1.2 The Command 二、使用Accelerate加载超大模型2.1 模型加载的常规流程2.2 加载空模型2.3 分片检查点&#xff08;Sharded checkpoints&#xff09;2.4 示例&#xff1a;使用Accelerate推理GPT2-1.5B2.5 device_map 三、bitsandbytes量…

LeetCode【13】罗马数字转整数

题目&#xff1a; 思路&#xff1a; 第十二题的逆运算&#xff0c;方法同理。需要注意的是IV、IX、XL、XC、CD、CM这六种特殊的情况。正常情况下每个字符找到对应的数值累加&#xff0c;这六种特殊字符都是左边的数值比右边的数值小。 这里以IV举例&#xff0c;IV对应数字是1和…

详解如何使用Jenkins一键打包部署SpringBoot项目

目录 1、Jenkins简介 2、Jenkins的安装及配置 2.1、Docker环境下的安装​编辑 2.2、Jenkins的配置 3、打包部署SpringBoot应用 3.1、在Jenkins中创建执行任务 3.2、测试结果 1、Jenkins简介 任何简单操作的背后&#xff0c;都有一套相当复杂的机制。本文将以SpringBoot应…

文本向量化

文本向量化表示的输出比较 import timeimport torch from transformers import AutoTokenizer, AutoModelForMaskedLM, AutoModel# simcse相似度分数 def get_model_output(model, tokenizer, text_str):"""验证文本向量化表示的输出:param model: 模型的…