Flutter中数据库的使用教程详解
作者:老李code 发布时间:2023-12-09 11:16:28
在Flutter开发过程中,我门有时候需要对一些数据进行本地的持久化存储,使用sp文件形式虽然也能解决问题,但是有时数据量较大的时候,显然我们文件形式就不太合适了,这时候我们就需要使用数据库进行存储,我们知道在原生中有系统提供的轻量级sqlite
数据库,在Flutter强大的生态环境中,也有这样一个数据库插件sqflite: ^2.0.2
可以同时在Androud、iOS
中进行数据库操作。
1、 创建数据库:这里我以存储我的搜索历史记录为例。
首先导入:
import 'package:sqflite/sqflite.dart';
这里我创建了一个数据库帮助类,为了以后数据库更新、升级等作准备:
代码实现:主要是对Database这个类的获取进行了封装。
/// 数据库帮助类
class DbHelper {
final String path = "laoli.db"; // 数据库名称 一般不变
//数据库中的表名字 这里是我存错历史搜索记录的表
static final searchTab = "SearchHistory";
//私有构造
DbHelper._();
static DbHelper? _instance;
static DbHelper get instance => _getInstance();
factory DbHelper() {
return instance;
}
static DbHelper _getInstance() {
if (_instance == null) {
_instance = DbHelper._();
}
return _instance ?? DbHelper._();
}
/// 数据库默认存储的路径
/// SQLite 数据库是文件系统中由路径标识的文件。如果是relative,
/// 这个路径是相对于 获取的路径getDatabasesPath(),
/// Android默认的数据库目录,
/// iOS/MacOS的documents目录。
Future<Database>? _db;
Future<Database>? getDb() {
_db ??= _initDb();
return _db;
}
// Guaranteed to be called only once.保证只调用一次
Future<Database> _initDb() async {
// 这里是我们真正创建数据库的地方 vserion代表数据库的版本,如果版本改变
//,则db会调用onUpgrade方法进行更新操作
final db =
await openDatabase(this.path, version: 1, onCreate: (db, version) {
// 数据库创建完成
// 创建表 一个自增id 一个text
db.execute("create table $searchTab (id integer primary key autoincrement, name text not null)");
}, onUpgrade: (db, oldV, newV) {
// 升级数据库调用
/// db 数据库
/// oldV 旧版本号
// newV 新版本号
// 升级完成就不会在调用这个方法了
});
return db;
}
// 关闭数据库
close() async {
await _db?.then((value) => value.close());
}
}
在java
后台开发过程中,数据库肯定都会分层设计,这样的好处可以在使用的过程中极大的提高代码的健壮性以及降低后期的维护成本,在移动前端虽然我们用数据库的地方跟后台相比少之又少,但是我还是建议也对数据库进行分层处理操作,虽然不分层也能实现,但是这样也可以降低我们的对于代码的维护成本以及良好的编程习惯。废话不多说,接下来我们需要创建处理数据的dao
层。
这里sqflite
封装了一些常用的sql
语法,比如增删改查,我们就不需要自己去写sql语法了,这里我简答封装了下增删改查的方法。
具体代码:
/// 数据操作类
class DbSearchHistoryDao {
/// 增
static insert(String text) {
// 去重
queryAll().then((value) {
bool isAdd = true;
for (var data in value) {
if (data.name == text) {
isAdd = false;
break;
}
}
if (isAdd) {
DbHelper.instance.getDb()?.then((value) => value.insert(
DbHelper.searchTab,
DbSearchHotBean(name: text).toJson(),
));
}
});
}
/// 删 全部
static deleteAll() {
DbHelper.instance.getDb()?.then((value) => value.delete(
DbHelper.searchTab,
));
}
/// 更新数据 通过id更新表内具体行的数据
static update(DbSearchHotBean dbSearchHotBean) {
DbHelper.instance.getDb()?.then((value) => value.update(
DbHelper.searchTab,
dbSearchHotBean.toJson(),//具体更新的数据
where: "id = ?"//通过id查找需要更新的数据
,whereArgs: [dbSearchHotBean.id]
));
}
/// 通过name查具体的实体类
static Future<DbSearchHotBean?> getBean(String name) async {
var db = await DbHelper.instance.getDb();
var maps = await db?.query(DbHelper.searchTab,
columns: ['id','name'],// 获取实体类的哪些字段 默认全部
where: 'name = ?',//通过实体类中的name字段
whereArgs: [name]);//具体name的值 限定数据
if(maps!=null && maps.length > 0) {
return DbSearchHotBean.fromJson(maps.first);
}
return null;
}
/// 查 全部all
static Future<List<DbSearchHotBean>> queryAll() async {
List<DbSearchHotBean> list = [];
await DbHelper.instance
.getDb()
?.then((db) => db.query(DbHelper.searchTab).then((value) {
for (var data in value) {
list.add(DbSearchHotBean.fromJson(data));
}
}));
return list;
}
}
实体类:虽然只有一个字段,但是创建实体类方便以后扩展。
class DbSearchHotBean {
int? id;
String? name; // 搜索词
DbSearchHotBean({this.id,required this.name});
DbSearchHotBean.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
}
Map<String, String?> toJson() {
var map = <String, String?>{};
map['id'] = id?.toString() ;
map['name'] = name ?? "";
return map;
}
}
具体用法就非常简单了:
增:DbSearchHistoryDao.insert(”搜索词“);
删全部:DbSearchHistoryDao.deleteAll();
改:例如将水改为火, 找到水的实体通过自增id修改name
DbSearchHistoryDao.getBean("水").then((value){
if(value!=null){
DbSearchHistoryDao.update(DbSearchHotBean(id: value.id,name: "火"));
}
});
查全部:await DbSearchHistoryDao.queryAll();
到这里数据库的基本用法就介绍完了,当然部分操作比如删指定数据,批量修改、批量删除等操作可以用 到批处理操作,这里就不过多介绍了,有需要的可以查看作者文档。链接
batch = db.batch();
batch.insert('Test', {'name': 'item'});
batch.update('Test', {'name': 'new_item'}, where: 'name = ?', whereArgs: ['item']);
batch.delete('Test', where: 'name = ?', whereArgs: ['item']);
results = await batch.commit();
总结
数据库操作总体上没什么难度,但是当我们数据量比较多的时候,数据表结构的设计就有一定的技术含量了,还有就是我们对于一些sql语句的掌握,因为此插件帮我们封装了常用的功能,如果有比较特殊的需求,还是需要我们掌握一定的sql语法才行,这里就简单的介绍一些常用的方法,在移动前端估计也基本够用了~
来源:https://juejin.cn/post/7084536128077824037


猜你喜欢
- 本文实例为大家分享了Unity Shader实现3D翻页效果的具体代码,供大家参考,具体内容如下参考文章:UnityShader使用Plan
- 本文实例为大家分享了Java实现图形化界面日历的具体代码,供大家参考,具体内容如下此程序主要功能实现了可以根据用户选择的年月日来定位日期,日
- 一、概述1.1 什么是Java工厂模式Java工厂模式是一种创建对象的设计模式,它提供了一种方法,通过该方法可以在不暴露对象创建逻辑的情况下
- 今天就来拿贪吃蛇小游戏来练练手吧!贪吃蛇游戏规则: 1.按下空格键(游戏未结束)则游戏
- idea工具使用 Java Exception Breakpoint 添加异常断点,在IDE里,新建一个断点,类型是Java Excepti
- Spring AOP底层原理代理模式一、什么是 AOPAOP 就是面向切面编程,是 OOP(面向对象编程)的延续。利用 AOP 可以对业务逻
- 本文实例讲述了C++判断一个链表是否为回文结构的方法。分享给大家供大家参考,具体如下:题目:给定一个链表头节点head,请判断是否为回文结构
- 前言通过adb shell input可以模拟android各种输入事件,比如文字、按键、触摸等等。adb shell inputUsage
- 概述java中的序列化可能大家像我一样都停留在实现Serializable接口上,对于它里面的一些核心机制没有深入了解过。直到最近在项目中踩
- 代码MyCalculator.h#pragma once#include <QtWidgets/QMainWindow>#inc
- 意图:想将项目用到的两个dll库文件(CryptEnDe.dll和ICSharpCode.SharpZipLib.dll)一同编译进exe中
- 前言Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring Mybatis在
- 在学习C#语言的时候,首先要学习控制台的应用程序,这样才能专注于语言的学习,减少学习的梯度,也有利于输出自己需要输出的内容。因此第一步学习C
- 前言最近在逛博客的时候看到了有关Redis方面的面试题,其中提到了Redis在内存达到最大限制的时候会使用LRU等淘汰机制,然后找了这方面的
- springboot整合redis主从sentinel一主二从三sentinel配置1、master:127.0.0.1:63792、sla
- 在使用线程池的时候,发现除了execute()方法可以执行任务外,还发现有一个方法submit()可以执行任务。submit()有3个参数不
- 实践过程效果代码public partial class FrmGetColor : Form{ public F
- 一、图示二、MapStructpom文件 <dependency> &n
- application.properties大家都不陌生,我们在开发的时候,经常使用它来配置一些可以手动修改而且不用编译的变量,这样的作用在
- 效果图国际惯例,先看效果图:具体效果就是吃豆人会根据吃不同颜色的豆子改变身体的颜色。绘制静态吃豆人、豆豆、眼睛首先,我们需要将这个静态的吃豆