Flutter 数据持久化存储之Hive
Flutter 数据持久化存储之Hive
- 前言
- 正文
- 一、配置项目
- 二、UI
- ① 增加UI
- ② 显示和删除UI
- 三、使用Hive
- ① 初始化Hive
- ② TypeAdapter自定义对象
- ③ 注册TypeAdapter
- ③ CURD
- 四、源码
前言
在Flutter中,有多种方式可以进行数据持久化存储。以下是一些常见的方式:
-
Shared Preferences:
使用shared_preferences插件,可以将数据存储在设备的轻量级持久化存储中。这种方式适合存储少量简单的键值对数据,比如用户偏好设置等。 -
文件存储:
使用dart:io库可以进行文件存储,可以将数据以文件的形式存储在设备上。这种方式适合存储结构化数据,可以使用JSON格式或者其他格式进行数据的读写。 -
SQLite数据库:
可以使用sqflite插件在Flutter应用中使用SQLite数据库。SQLite是一种轻量级的关系型数据库,适合于需要存储结构化数据,并进行高效查询的场景。 -
NoSQL数据库:
一些Flutter插件(如moor)也提供了对NoSQL数据库的支持,比如使用对象数据库(如Hive)来存储数据。 -
云存储:
通过与云存储(如Firebase Firestore、AWS Amplify等)进行集成,可以将数据存储在云端,实现跨设备数据同步和备份。
以上的这些我们都不使用,这里要使用的是Hive库,地址是 Hive,感兴趣的可以自行了解,本文运行效果图。
正文
Hive是一个轻量级、快速的本地数据库解决方案,适用于在移动应用程序中进行数据持久化存储。Hive采用高效的自定义序列化算法,能够在移动设备上快速读写数据,适用于处理结构化数据。并且Hive是用纯Dart编写的,这使得它比不支持Flutter网络的SQLite更有优势。
一、配置项目
首先我们创建一个名为study_hive
的项目。
创建项目之后,我们配置一下依赖库,在项目的pubspec.yaml文件中,添加如下所示代码:
dependencies:get:hive:hive_flutter:dev_dependencies:hive_generator:build_runner:
在dependencies
中我添加了get和hive的库,在dev_dependencies中添加了一个构建对象的依赖库。冒号后面没有写版本号就是获取该库最新的版本。添加位置如下图所示:
然后点击Pub get获取对应的依赖库即可,到这里为止我们的配置工作就完成了。
二、UI
在使用Hive库时我们需要想一下,用这个库去做什么?先设想一个应用场景,而不是写到哪里就是哪里,乱枪打鸟不可取。我们就写这样一个场景,对于人员信息的操作,可以增加、查询、修改、删除、删除所有。基于这个场景我们就可以去设计UI了,我们尽量在一个页面去解决,更直观一些(PS:我也是偷一个懒)。
首先我们在lib目录下新建一个page包,page包下新建一个hive_page.dart
,里面的代码如下:
import 'package:flutter/material.dart';class HivePage extends StatelessWidget {Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text("Hive Demo"),),body: Container(color: Colors.blue,),);}
}
当前页面很简单,就是一个标题和蓝色背景,当然你现在还看不到的,我们需要修改一下main.dart中的代码:
import 'package:flutter/material.dart';
import 'package:study_hive/page/hive_page.dart';void main() async {runApp(const MyApp());
}class MyApp extends StatelessWidget {const MyApp({super.key});Widget build(BuildContext context) {return MaterialApp(title: 'Hive Demo',theme: ThemeData(primaryColor: Colors.blueAccent,appBarTheme: const AppBarTheme(elevation: 0),),home: HivePage(),);}
}
这里的修改就是去掉了原来默认代码,并且加载我们刚写好的HivePage
,下面我们可以运行一下,虚拟器或者真机都可以。
① 增加UI
在HivePage的build()中增加如下代码:
///通用输入框Widget baseEdit(String hintText, TextInputType type,TextEditingController textController) {return Container(decoration: BoxDecoration(borderRadius: BorderRadius.circular(10),border: Border.all(color: Colors.black87,width: 1.0,),),margin: const EdgeInsets.only(top: 6),padding: const EdgeInsets.all(0),height: 44,child: TextField(textInputAction: TextInputAction.none,keyboardType: type,cursorColor: Colors.black87,cursorWidth: 1,controller: textController,decoration: InputDecoration(contentPadding: const EdgeInsets.only(left: 10),filled: true,fillColor: Colors.white,hintText: hintText,hintStyle: const TextStyle(textBaseline: TextBaseline.alphabetic,color: Colors.grey,),border: OutlineInputBorder(borderRadius: BorderRadius.circular(10),borderSide: BorderSide.none,),),),);}
这里的代码就是构建一个输入框的组件,将里面的提示文本、键盘类型和输入框控制器抽离了出来。控制器我们就放到GetX中使用,在page包下新建一个hive_controller.dart
,代码如下所示:
import 'package:flutter/material.dart';
import 'package:get/get.dart';class HiveController extends GetxController {late TextEditingController nameEditController,ageEditController;void onInit() {super.onInit();nameEditController = TextEditingController();ageEditController = TextEditingController();}
}
这里主要就是对于输入框控制器的初始化。回到HivePage的build中再写两个组件,代码如下:
var size4 = const SizedBox(height: 4,width: 4,);///保存按钮var saveBtn = TextButton(onPressed: () {print('Save');},child: const Text('Save',style: TextStyle(color: Colors.blue),));
一个是间隔,一个是保存按钮,然后我们可以再写一个组件用来包含刚才所写的内容。这里面就需要用到baseEdit去构建两个输入框,因此我们加上GetX,在page包下新建一个hive_controller.dart
,代码如下所示:
import 'package:flutter/material.dart';
import 'package:get/get.dart';class HiveController extends GetxController {late TextEditingController nameEditController,ageEditController;void onInit() {super.onInit();nameEditController = TextEditingController();ageEditController = TextEditingController();}
}
回到HivePage中,在build中增加一个组件,代码如下:
///保存组件var saveWidget = Container(width: MediaQuery.of(context).size.width,margin: const EdgeInsets.all(8),padding: const EdgeInsets.all(8),decoration: BoxDecoration(color: Colors.white,borderRadius: BorderRadius.circular(12.0),),child: Column(mainAxisSize: MainAxisSize.min,children: [baseEdit('Name', TextInputType.name, controller.nameEditController),size4,baseEdit('Age', TextInputType.number, controller.ageEditController),saveBtn],),);
最后我们再修改一下返回的Scaffold
中的代码,在这里我们加载刚才写好的保存组件,如下所示:
return Scaffold(appBar: AppBar(title: const Text("Hive Demo"),),body: Container(color: Colors.blue,child: Column(children: [saveWidget],),),);
这里你需要注意的就是代码的顺序了,当前这个组件在最下边,通过一张图来说明。
运行一下:
这样增加的UI就写好了,下面我们构建显示和删除的。
② 显示和删除UI
在build中添加如下代码:
///列表组件var listWidget = Expanded(child: Container(width: MediaQuery.of(context).size.width,// 允许高度自适应margin: const EdgeInsets.only(left: 8, right: 8, bottom: 8),padding: const EdgeInsets.all(8),decoration: BoxDecoration(color: Colors.white,borderRadius: BorderRadius.circular(12.0),),));var deleteAllBtn = ElevatedButton(onPressed: () {print('DeleteAll');},child: const Row(mainAxisSize: MainAxisSize.min,children: [Icon(Icons.delete, color: Colors.red),SizedBox(width: 4),Text('DeleteAll',style: TextStyle(color: Colors.red),)],));
再修改一下返回的Scaffold,将列表和按钮组件添加进去,代码如下所示:
return Scaffold(appBar: AppBar(title: const Text("Hive Demo"),),body: Container(color: Colors.blue,child: Column(children: [saveWidget, listWidget, deleteAllBtn],),),);
再保存一下,热重载,效果如图所示:
三、使用Hive
下面我们就可以开始使用Hive了,之前我们已经添加过依赖了,下面我们首先进行初始化。
① 初始化Hive
在Flutter中使用Hive,我们需要在main()
函数中进行初始化,注意导包语句:
import 'package:hive_flutter/hive_flutter.dart';
main()
函数代码如下所示:
void main() async {//初始化Hiveawait Hive.initFlutter();runApp(const MyApp());
}
初始化之后我们就可以去使用了,在此之前我们需要明确使用的方式,因为我们操作的是对象,包含常规的数据类型,因此我们就需要自定义对象。
② TypeAdapter自定义对象
在lib
下创建一个models
目录,该目录下创建person.dart文件,代码如下:
class Person {String name;int age;Person({required this.name,required this.age});
}
这是标准的对象代码,然后我们可以使用Hive注释这个类和类里面的变量,然后快速生成一个TypeAdapter类代码,下面我们修改一下Person的代码如下:
import 'package:hive/hive.dart';part 'person.g.dart';(typeId: 1)
class Person {(0)String name;(1)int age;Person({required this.name, required this.age});
}
首先注意导包的语句,这里的part 'person.g.dart';
语句会标红,这是因为目前还没有这个文件,这个文件就是我们需要快捷生成的。HiveType 和 HiveField 是 Hive 数据库中用来定义对象映射和序列化的注解。
-
HiveType:
HiveType
是一个标记注解,用于标识 Hive 中的自定义对象类。它告诉 Hive 数据库,被注解的类是一个 Hive 对象,需要进行序列化和反序列化。- 当你在定义自己的模型类时,可以使用
@HiveType()
注解来标记这个类,以便 Hive 可以识别并处理这个类。 - 所有的 typeId 允许在 0 到 223 之间,不可以重复。
-
HiveField:
HiveField
是用来标记类中的字段(成员变量)的注解,用于指定字段在 Hive 数据库中的位置和顺序。- 当你在定义自己的模型类时,可以使用
@HiveField()
注解来标记类中的字段,以便 Hive 可以按照指定的顺序进行序列化和反序列化。 - 字段编号的范围可为 0~255,不可以重复。
下面我们通过在Terminal
中输入一行代码,生成对应的TypeAdapter对象类,代码如下所示:
flutter packages pub run build_runner build
输入后回车,如下图所示:
你会看到对应的person.g.dart
文件就已经生成在models
文件夹中,里面的代码如下所示:
// GENERATED CODE - DO NOT MODIFY BY HANDpart of 'person.dart';// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************class PersonAdapter extends TypeAdapter<Person> {final int typeId = 1;Person read(BinaryReader reader) {final numOfFields = reader.readByte();final fields = <int, dynamic>{for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),};return Person(name: fields[0] as String,age: fields[1] as int,);}void write(BinaryWriter writer, Person obj) {writer..writeByte(2)..writeByte(0)..write(obj.name)..writeByte(1)..write(obj.age);} int get hashCode => typeId.hashCode; bool operator ==(Object other) =>identical(this, other) ||other is PersonAdapter &&runtimeType == other.runtimeType &&typeId == other.typeId;
}
下面我们注册TypeAdapter对象
③ 注册TypeAdapter
依然是修改main()
函数,注意一点,在打开使用Hive的盒子之前,需要先注册TypeAdapter,代码如下所示:
import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:study_hive/models/person.dart';
import 'package:study_hive/page/hive_page.dart';void main() async {//初始化Hiveawait Hive.initFlutter();//注册TypeAdapterHive.registerAdapter(PersonAdapter());//打开盒子await Hive.openBox<Person>('personBox');runApp(const MyApp());
}
注意导包语句,现在我们的盒子就打开了,盒子名称是personBox,这个可以自己去定义的,下面我们就可以正式去使用这个盒子来进行CURD了。
③ CURD
在进行CURD时,我们将代码写在GetxController中,提供相关的函数进行操作,下面我们修改一下HiveController
中的代码:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:study_hive/models/person.dart';class HiveController extends GetxController {late TextEditingController nameEditController, ageEditController;final personBox = Hive.box<Person>('personBox');void onInit() {super.onInit();nameEditController = TextEditingController();ageEditController = TextEditingController();}void save() {var person = Person(name: nameEditController.text, age: int.parse(ageEditController.text));personBox.add(person);nameEditController.clear();ageEditController.clear();}void modify(int index, Person person) {personBox.putAt(index, person);}void delete(int index) {personBox.deleteAt(index);}void deleteAll() {personBox.clear();}void onClose() {nameEditController.dispose();ageEditController.dispose();super.onClose();}
}
上面的代码解释一下,首先我们获取personBox盒子对象,final personBox = Hive.box<Person>('personBox');
,然后就是save()
函数中获取输入框的值进行保存,保存之后再清空输入框,这里就没有对输入框的内容判空处理,需要注意一下。modify()
函数中通过下标和person对象就可以完成,删除和删除所有就是可以直接处理的,就没有什么好说的。你会发现没有查询,这是因为Hive提供了一个名为ValueListenableBuilder
的小部件,它只在数据库内的任何数值被修改时才会刷新。下面我们就可以在HivePage中去使用刚才所写的函数。
首先我们修改一下listWidget
组件的代码:
var listWidget = Expanded(child: Container(width: MediaQuery.of(context).size.width,margin: const EdgeInsets.only(left: 8, right: 8, bottom: 8),padding: const EdgeInsets.all(8),decoration: BoxDecoration(color: Colors.white,borderRadius: BorderRadius.circular(12.0),),child: ValueListenableBuilder(valueListenable: controller.personBox.listenable(),builder: (context, box, widget) {if (box.isEmpty) {return const Center(child: Text('Empty'),);} else {return ListView.builder(itemCount: box.length,itemBuilder: (context, index) {var personData = box.getAt(index)!;return ListTile(title: Text(personData.name),subtitle: Text(personData.age.toString()),trailing: Row(mainAxisSize: MainAxisSize.min,children: <Widget>[IconButton(icon: const Icon(Icons.edit),onPressed: () {showModifyDialog(index, personData);},),IconButton(icon: const Icon(Icons.delete),onPressed: () {controller.delete(index);},),],),);});}})));
这里的核心代码就是ValueListenableBuilder
的使用,这里我们判断了box是否为空,空就显示文字提示一下,不为空就构建一个ListView显示Item数据。如下图所示:
在列表的Item中我们除了显示用户的名称和年龄之外还有两个功能按钮,分别用于修改和删除,如下图所示:
针对于删除很简单之后调用控制器里面写好的函数就可以了,删除之后列表会自动刷新的。而修改的话屏幕上没有空间了,因此我就写一个弹窗去显示需要修改的内容,代码如下所示:
void showModifyDialog(int index, Person personData) => showDialog(context: context,builder: (BuildContext context) {TextEditingController nameController =TextEditingController(text: personData.name);TextEditingController ageController =TextEditingController(text: personData.age.toString());return AlertDialog(title: const Text('Modify Data'),content: Column(mainAxisSize: MainAxisSize.min,children: [TextField(controller: nameController),TextField(controller: ageController)],),actions: [ElevatedButton(child: const Text('Modify'),onPressed: () {var person = Person(name: nameController.text,age: int.parse(ageController.text));controller.modify(index, person);Navigator.of(context).pop(); // 关闭对话框})],);});
弹窗修改之后就关闭弹窗。最后我们再修改一下保存按钮和删除所有按钮组件的代码,如下所示:
var saveBtn = TextButton(onPressed: () {controller.save();},child: const Text('Save',style: TextStyle(color: Colors.blue),));var deleteAllBtn = ElevatedButton(onPressed: () {controller.deleteAll();},child: const Row(mainAxisSize: MainAxisSize.min,children: [Icon(Icons.delete, color: Colors.red),SizedBox(width: 4),Text('DeleteAll',style: TextStyle(color: Colors.red),)],));
那么基本上代码就写完了,下面我们整体看一下运行效果。
效果符合我的预期,文章到这里就结束了,元宵节快乐呀!
四、源码
源码地址:study_hive
相关文章:

Flutter 数据持久化存储之Hive
Flutter 数据持久化存储之Hive 前言正文一、配置项目二、UI① 增加UI② 显示和删除UI 三、使用Hive① 初始化Hive② TypeAdapter自定义对象③ 注册TypeAdapter③ CURD 四、源码 前言 在Flutter中,有多种方式可以进行数据持久化存储。以下是一些常见的方式࿱…...
Java中继承静态属性,方法,和非静态属性和方法的继承区别
结论: Java中静态属性和静态方法是可以被继承的,但是不可以被重写,而是被隐藏。 Java中非静态属性,可以被继承,但是不可以被重写,而是被隐藏。 Java中非静态方法,可以被继承,可以…...

C# If与Switch的区别
在 switch 语句中使用表达式比较时,编译器会生成一个查找表,其中包含所有表达式的值和对应的 case 标签。因此,与使用常量或字面量比较相比,使用表达式比较可能会略微降低性能。 只有当 switch 语句中的所有 case 标签都使用常量或…...

实验室预约|实验室预约小程序|基于微信小程序的实验室预约管理系统设计与实现(源码+数据库+文档)
实验室预约小程序目录 目录 基于微信小程序的实验室预约管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、微信小程序前台 2、管理员后台 (1)管理员登录 (2)实验室管理 (3)公告信息…...

蓝桥杯DP算法——区间DP(C++)
根据题意要求的是将石子合并的最小权值,我们可以根据DP思想使用二维数组f[i,j]来存放所有从第i堆石子到第j堆石子合并成一堆石子的合并方式。 然后由第二个图所示,我们可以将i到j区间分成两个区间,因为将i到j合并成一个区间的前一步一定是合…...

pytest结合Allure生成测试报告
文章目录 1.Allure配置安装2.使用基本命令报告美化1.**前置条件**2.**用例步骤****3.标题和描述****4.用例优先级**3.进阶用法allure+parametrize参数化parametrize+idsparametrize+@allure.title()4.动态化参数5.环境信息**方式一****方式二**6.用例失败截图1.Allure配置安装 …...

Linux--ACL权限管理
一.ACL权限管理简介 ACL(Access Control List,访问控制列表)是一种文件权限管理机制,它提供了比传统的UGO(用户、组、其他)权限更灵活的权限设置方式。以下是ACL的一些主要功能: 针对特定用户或…...

Xcode中App图标和APP名称的修改
修改图标 选择Assets文件 ——> 点击Applcon 换App图标 修改名称 点击项目名 ——> General ——> Display Name...

Spring 手动实现Spring底层机制
目录 一、前言 二、Spring底层整体架构 1.准备工作 : 2.架构分析 : (重要) 3.环境搭建 : 三、手动实现Spring容器结构 1.自定义注解 : 1.1 Component注解 1.2 Scope注解 2.自定义组件 : 3.自定义用于封装Bean信息的BeanDefinition类&a…...
CSV数据导入到ClickHouse数据库
问题描述:手头上有一个数据量较大的CSV文件,希望导入到指定的ClickHouse数据中,ClickHouse部署在服务器中。 解决方案:通常来说,数据量较少的CSV文件可以直接通过DBeaver软件的可视化界面导入数据。 若数据量较大&…...

第十二天-ppt的操作
目录 创建ppt文档 安装 使用 段落的使用 段落添加数据 段落中定义多个段落 自定义段落 ppt插入表表格 PPT插入图片 读取ppt 读取ppt整体对象 编辑 获取ppt文本 获取表格内容 创建ppt文档 安装 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple python…...

计算机网络-网络层,运输层,应用层
网络层/网际层 网络层的主要任务包括: 提供逻辑上的端到端通信:网络层负责确定数据的传输路径,使数据能够从源主机传输到目标主机,即实现端到端的通信。数据包的路由和转发:网络层根据目标主机的地址信息,…...

Python爬虫学习
1.1搭建爬虫程序开发环境 爬取未来七天天气预报 from bs4 import BeautifulSoup from bs4 import UnicodeDammit import urllib.request url"http://www.weather.com.cn/weather/101120901.shtml" try:headers{"User-Agent":"Mozilla/5.0 (Windows …...

台式电脑黑屏无法开机怎么办 电脑开机黑屏的解决方法
经常有朋友电脑一开机,发现电脑黑屏没法用了。很多人看到黑屏就懵了,以为电脑要报废了,这是什么原因?电脑开机黑屏怎么解决?一般常说的黑屏故障分为两种,显示屏没有任何显示以及显示英文。下面小编要为大家带来的是台式电脑黑屏…...

【Docker】初学者 Docker 基础操作指南:从拉取镜像到运行、停止、删除容器
在现代软件开发和部署中,容器化技术已经成为一种常见的方式,它能够提供一种轻量级、可移植和可扩展的应用程序打包和部署解决方案。Docker 是目前最流行的容器化平台之一,它提供了一整套工具和技术,使得容器的创建、运行和管理变得…...
突破编程_C++_面试(数组(1))
面试题1:详细说明一下数组名是什么? 在 C 中,数组名代表数组首元素的地址。更具体地说,数组名是一个指向数组第一个元素的常量指针。这意味着,当使用数组名时,实际上是在使用指向数组第一个元素的指针。 例…...

基于springboot+vue的靓车汽车销售网站(前后端分离)
博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战,欢迎高校老师\讲师\同行交流合作 主要内容:毕业设计(Javaweb项目|小程序|Pyt…...

【知识整理】Git Commit Message 规范
一. 概述 前面咱们整理过 Code Review 一文,提到了 Review 的重要性,已经同过gitlab进行CodeReview 的方式,那么本文详细说明一下对CodeReivew非常重要的Git Commit Message 规范。 我们在每次提交代码时,都需要编写 Commit Mes…...

HarmonyOS学习--三方库
文章目录 一、三方库获取二、常用的三方库1. UI库:2. 网络库:3. 动画库: 三、使用开源三方库1. 安装与卸载2. 使用 四、问题解决1. zsh: command not found: ohpm 一、三方库获取 在Gitee网站中获取 搜索OpenHarmony-TPC仓库,在t…...

【服务器数据恢复】FreeNAS+ESXi虚拟机数据恢复案例
服务器数据恢复环境: 一台服务器通过FreeNAS(本案例使用的是UFS2文件系统)实现iSCSI存储,整个UFS2文件系统作为一个文件挂载到ESXi虚拟化系统(安装在另外2台服务器上)上。该虚拟化系统一共有5台虚拟机&…...

UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...

听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...