Android Jetpack之用Room+ViewModel+LiveData实现增删改查数据(createFromAsset())

文章目录

  • 一、Room简介
  • 二、用Room+ViewModel+LiveData增删改查数据
  • 三、下载源码

一、Room简介

RoomGoogle推出的数据库框架,是一个 ORM (Object Relational Mapping)对象关系映射数据库、其底层还是对SQLite的封装。

Room包含三个主要组件:

  • 数据库类(DataBase),用于保存数据库并作为应用持久性数据底层连接的主要访问点。
  • 数据实体(Entity),用于表示应用的数据库中的表。
  • 数据访问对象 (DAO),提供您的应用可用于查询、更新、插入和删除数据库中的数据的方法。
  • @Entity 表结构实体
  • @PrimaryKey 主键
  • @ColumnInfo 列/字段信息

二、用Room+ViewModel+LiveData增删改查数据

EntityDaoDatabase 操作数据库
数据库的每个表,都对应一个Entity,一个DaoDao负责增删改查操作)

项目RoomDemo,如下图:

build.gradle添加如下依赖:

plugins {id 'com.android.application'id 'kotlin-android'id 'kotlin-android-extensions'id 'kotlin-kapt'
}dependencies {def room_version = "2.3.0"implementation "androidx.room:room-runtime:$room_version"annotationProcessor "androidx.room:room-compiler:$room_version"kapt "androidx.room:room-compiler:$room_version"
}

首先,创建一个数据表Student。先创建包名,在com.bignerdranch.roomdemo下创建一个db包,db下创建bean包,bean包下创建Student类。

package com.bignerdranch.roomdemo.db.beanimport androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.PrimaryKey
import org.jetbrains.annotations.NotNull@Entity(tableName = "student")
class Student {@NotNull@PrimaryKey(autoGenerate = true)@ColumnInfo(name = "id", typeAffinity = ColumnInfo.INTEGER)var id = 0@NotNull@ColumnInfo(name = "name", typeAffinity = ColumnInfo.TEXT)var name: String@NotNull@ColumnInfo(name = "age", typeAffinity = ColumnInfo.TEXT)var age: String/*** Room会使用这个构造器来存储数据,也就是当你从表中得到Student对象时候,Room会使用这个构造器*/constructor(id: Int, name: String, age: String) {this.id = idthis.name = namethis.age = age}/*** 由于Room只能识别和使用一个构造器,如果希望定义多个构造器,你可以使用Ignore标签,让Room忽略这个构造器* 同样,@Ignore标签还可用于字段,使用@Ignore标签标记过的字段,Room不会持久化该字段的数据*/@Ignoreconstructor(name: String, age: String) {this.name = namethis.age = age}
}

这个@Entity就是表示数据库中的表,Student类对应就是Student表,@PrimaryKey表示主键,这里是idautoGenerate = true 是自增,@NonNull表示不为空。 @ColumnInfo表示表中的列名,name = "name"表示列名的值。

下面在db包下新建一个dao包,创建StudentDao,里面的代码如下:

package com.bignerdranch.roomdemo.db.daoimport androidx.lifecycle.LiveData
import androidx.room.*
import com.bignerdranch.roomdemo.db.bean.Student@Dao
interface StudentDao {@Insertfun insertStudent(student: Student?)@Deletefun deleteStudent(student: Student?)@Updatefun updateStudent(student: Student?)@Query("SELECT * FROM student")fun getStudentList(): LiveData<List<Student?>?>? //希望监听学生表的变化,为其加上LiveData@Query("SELECT * FROM student WHERE id = :id")fun getStudentById(id: Int): Student?
}

StudentDao是一个接口,主要是定义了一些方法,通过注解在编译的时候会生成实现类。
然后,新建main/assets/databases,并在其中放置student.db文件,其位置如下:

SQLite软件导入students.db文件,如下图:

然后,在MyDatabase.kt中,用createFromAsset()方法从assets/database/students.db创建Room数据库,下面是数据库的创建,在db包下新建一个MyDatabase类,继承RoomDatabase,代码如下:

package com.bignerdranch.roomdemo.dbimport android.content.Context
import android.util.Log
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import com.bignerdranch.roomdemo.db.bean.Student
import com.bignerdranch.roomdemo.db.dao.StudentDao@Database(entities = [Student::class], exportSchema = false, version = 1)
abstract class MyDatabase() : RoomDatabase() {abstract fun studentDao(): StudentDao?companion object {private val DATABASE_NAME = "my_db"private var databaseInstance: MyDatabase? = null@Synchronized //已同步fun getInstance(context: Context): MyDatabase? {if (databaseInstance == null) {databaseInstance = Room.databaseBuilder(context.applicationContext,MyDatabase::class.java,DATABASE_NAME).createFromAsset("databases/student.db").fallbackToDestructiveMigration()
//                    .addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_1_3, MIGRATION_3_4).build()}return databaseInstance}val MIGRATION_1_2: Migration = object : Migration(1, 2) {override fun migrate(database: SupportSQLiteDatabase) {//do somethingLog.d("MyDatabase", "MIGRATION_1_2")}}private val MIGRATION_2_3: Migration = object : Migration(2, 3) {override fun migrate(database: SupportSQLiteDatabase) {//do somethingLog.d("MyDatabase", "MIGRATION_2_3")}}private val MIGRATION_1_3: Migration = object : Migration(1, 3) {override fun migrate(database: SupportSQLiteDatabase) {//do somethingLog.d("MyDatabase", "MIGRATION_1_3")}}val MIGRATION_3_4: Migration = object : Migration(3, 4) {override fun migrate(database: SupportSQLiteDatabase) {Log.d("MyDatabase", "MIGRATION_3_4")database.execSQL("CREATE TABLE temp_Student (" +"id INTEGER PRIMARY KEY NOT NULL," +"name TEXT," +"age TEXT)")database.execSQL("INSERT INTO temp_Student (id, name, age) " +"SELECT id, name, age FROM Student")database.execSQL("DROP TABLE Student")database.execSQL("ALTER TABLE temp_Student RENAME TO Student")}}}
}

这里的@Database注解表示这个类是用来操作数据库的,entities = [Student::class]表示当前数据库中的表,只有一个Student表,多的表用应用逗号隔开。version = 1表示数据库的版本,可以做数据库的升级操作。createFromAsset()Room库中提供的。

注意这是一个抽象类,在编译时Room会帮助构建实现类。

现在运行一下,手机或者模拟器都可以。然后什么都不用去做。

可以查看到,MyDatabaseStudentDao的实现类都自动生成了。

ViewModel内:通过 Room.Database查到LiveData数据,在外部监听LiveData
Room变化时,通过ViewModel内的LiveData通知页面数据的变化,架构如下:

新建StudentViewModel类,该类继承自AndroidViewModel,其中有DatabaseLiveData,代码如下:

package com.bignerdranch.roomdemo.jetpackroomwithlivedataandviewmodeltestimport android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import com.bignerdranch.roomdemo.db.MyDatabase
import com.bignerdranch.roomdemo.db.bean.Studentclass StudentViewModel(application: Application) : AndroidViewModel(application) {private val myDatabase: MyDatabase?val liveDataStudent: LiveData<List<Student?>?>?init {myDatabase = MyDatabase.getInstance(application)liveDataStudent = myDatabase!!.studentDao()!!.getStudentList()}}

表操作无非就是那么几个,增删改查,但是为了更直观的显示结果,需要对UI做一些改动。

在工程的build.gradle中增加repositories闭包中增加jitpack库。

然后在appbuild.gradle中的dependencies{}比包中增加

implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.6'

1. 修改布局
Sync一下,下面修改一下页面的布局文件activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><Buttonandroid:id="@+id/btnInsertStudent"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:layout_margin="12dp"android:text="Add a Student"android:textAllCaps="false" /><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/recyclerView"android:layout_width="match_parent"android:layout_height="wrap_content" />
</LinearLayout>

在这里插入图片描述

这里就是一个按钮和一个列表,下面创建列表的item布局
layout下新建一个list_item_student.xml布局,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingTop="12dp"android:paddingBottom="12dp"><TextViewandroid:id="@+id/tvId"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center" /><TextViewandroid:id="@+id/tvName"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center" /><TextViewandroid:id="@+id/tvAge"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center" /></LinearLayout>

在这里插入图片描述

新建dialog_layout_student.xml,布局如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><EditTextandroid:id="@+id/etName"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="1"android:autofillHints=""android:hint="Name" /><EditTextandroid:id="@+id/etAge"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="1"android:autofillHints=""android:hint="Age" /></LinearLayout>

在这里插入图片描述

com.bignerdranch.roomdemo下新建一个adapter包,包下新建StudentAdapter类,作为列表数据的适配器。代码如下:
2. 列表适配器

package com.bignerdranch.roomdemo.adapterimport com.bignerdranch.roomdemo.R
import com.bignerdranch.roomdemo.db.bean.Student
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import kotlinx.android.synthetic.main.list_item_student.view.*class StudentAdapter(layoutResId: Int = R.layout.list_item_student) :BaseQuickAdapter<Student, BaseViewHolder>(layoutResId) {override fun convert(holder: BaseViewHolder, item: Student) {holder.itemView.run {tvId.text = item.id.toString()tvName.text = item.nametvAge.text = item.age}}
}

然后,在MainActivity中初始化List,实例化StudentViewModel并监听其LiveData的变化,代码如下:

package com.bignerdranch.roomdemoimport android.content.DialogInterface
import android.os.AsyncTask
import android.os.Bundle
import android.text.TextUtils
import android.view.View
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import com.bignerdranch.roomdemo.adapter.StudentAdapter
import com.bignerdranch.roomdemo.db.MyDatabase
import com.bignerdranch.roomdemo.db.bean.Student
import com.bignerdranch.roomdemo.jetpackroomwithlivedataandviewmodeltest.StudentViewModel
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.listener.OnItemLongClickListener
import kotlinx.android.synthetic.main.activity_main.recyclerView/**** @date*/
class MainActivity : AppCompatActivity(), OnItemLongClickListener {private val mStudentAdapter by lazy {StudentAdapter().apply {setOnItemLongClickListener(this@MainActivity)}}private var myDatabase: MyDatabase? = nullprivate var studentList: MutableList<Student>? = nulloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)findViewById<View>(R.id.btnInsertStudent).setOnClickListener {openAddStudentDialog()}studentList = ArrayList()val layoutManager = LinearLayoutManager(this@MainActivity)layoutManager.orientation = LinearLayoutManager.VERTICALrecyclerView.layoutManager = layoutManagerrecyclerView.adapter = mStudentAdapter
//        mStudentAdapter.setList(studentList)myDatabase = MyDatabase.getInstance(this)val studentViewModel: StudentViewModel =ViewModelProvider(this)[StudentViewModel::class.java]studentViewModel.liveDataStudent!!.observe(this) { students ->(studentList as ArrayList<Student?>).clear()(studentList as ArrayList<Student?>).addAll(students!!)
//            studentAdapter2!!.notifyDataSetChanged()mStudentAdapter.setList(studentList)mStudentAdapter.notifyDataSetChanged()}}private fun updateOrDeleteDialog(student: Student?) {val options = arrayOf("更新", "删除")AlertDialog.Builder(this@MainActivity).setTitle("").setItems(options) { _, which ->if (which == 0) {openUpdateStudentDialog(student)} else if (which == 1) {if (student != null) {DeleteStudentTask(student).execute()}}}.show()}private fun openAddStudentDialog() {val customView: View = this.layoutInflater.inflate(R.layout.dialog_layout_student, null)val etName = customView.findViewById<EditText>(R.id.etName)val etAge = customView.findViewById<EditText>(R.id.etAge)val builder = AlertDialog.Builder(this@MainActivity)val dialog = builder.create()dialog.setTitle("Add Student")dialog.setButton(DialogInterface.BUTTON_POSITIVE, "OK") { dialog, which ->if (TextUtils.isEmpty(etName.text.toString()) || TextUtils.isEmpty(etAge.text.toString())) {Toast.makeText(this@MainActivity, "输入不能为空", Toast.LENGTH_SHORT).show()} else {InsertStudentTask(etName.text.toString(), etAge.text.toString()).execute()}}dialog.setButton(DialogInterface.BUTTON_NEGATIVE,"CANCEL") { dialog, which -> dialog.dismiss() }dialog.setView(customView)dialog.show()}private fun openUpdateStudentDialog(student: Student?) {if (student == null) {return}val customView: View = this.layoutInflater.inflate(R.layout.dialog_layout_student, null)val etName = customView.findViewById<EditText>(R.id.etName)val etAge = customView.findViewById<EditText>(R.id.etAge)etName.setText(student.name)etAge.setText(student.age)val builder = AlertDialog.Builder(this@MainActivity)val dialog = builder.create()dialog.setTitle("Update Student")dialog.setButton(DialogInterface.BUTTON_POSITIVE, "OK") { dialog, which ->if (TextUtils.isEmpty(etName.text.toString()) || TextUtils.isEmpty(etAge.text.toString())) {Toast.makeText(this@MainActivity, "输入不能为空", Toast.LENGTH_SHORT).show()} else {UpdateStudentTask(student.id,etName.text.toString(),etAge.text.toString()).execute()}}dialog.setButton(DialogInterface.BUTTON_NEGATIVE,"CANCEL") { dialog, which -> dialog.dismiss() }dialog.setView(customView)dialog.show()}private inner class InsertStudentTask(var name: String, var age: String) :AsyncTask<Void?, Void?, Void?>() {override fun doInBackground(vararg params: Void?): Void? {myDatabase!!.studentDao()!!.insertStudent(Student(name, age))return null}}private inner class UpdateStudentTask(var id: Int, var name: String, var age: String) :AsyncTask<Void?, Void?, Void?>() {override fun doInBackground(vararg params: Void?): Void? {myDatabase!!.studentDao()!!.updateStudent(Student(id, name, age))return null}}private inner class DeleteStudentTask(var student: Student) : AsyncTask<Void?, Void?, Void?>() {override fun doInBackground(vararg params: Void?): Void? {myDatabase!!.studentDao()!!.deleteStudent(student)return null}}override fun onItemLongClick(adapter: BaseQuickAdapter<*, *>,view: View,position: Int): Boolean {updateOrDeleteDialog((studentList as ArrayList<Student?>)[position])return true}
}

运行后,当LiveData数据变化时,更新UI即可,而不需要每次增删改后都必须用QueryStudentTask() 来手动查询一次数据库,简化了系统,效果如下:

三、下载源码

下载源码github地址:https://github.com/caobin10/RoomDemo

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

润和软件HopeStage与亚信安全云主机深度安全防护系统完成产品兼容性互认证

近日&#xff0c;江苏润和软件股份有限公司&#xff08;以下简称“润和软件”&#xff09;HopeStage 操作系统与亚信科技&#xff08;成都&#xff09;有限公司&#xff08;以下简称“亚信安全”&#xff09;云主机深度安全防护系统完成兼容性测试。 测试结果表明&#xff0c;企…

golang并发安全-sync.map

sync.map解决的问题 golang 原生map是存在并发读写的问题&#xff0c;在并发读写时候会抛出异常 func main() {mT : make(map[int]int)g1 : []int{1, 2, 3, 4, 5, 6}g2 : []int{4, 5, 6, 7, 8, 9}go func() {for i : range g1 {mT[i] i}}()go func() {for i : range g2 {mT[…

Mysql 将数据按照年月分组 统计

要的效果: 方案&#xff1a; ① 使用 DATE_FORMAT(date, ‘%Y-%m-%d’) 函数 DATE_FORMAT 怎么去使用格式化&#xff0c;取决于后面的格式模式。 我们这里只是想区分到年 、月&#xff0c; 所以我们的sql 里面使用 %Y-%m : SELECT DATE_FORMAT(create_time, %Y-%m) AS …

Bind for 0.0.0.0:2379 failed: port is already allocated

1、执行命令docker-compose -p docker-apisix up -d 报错 Error response from daemon: driver failed programming external connectivity on endpoint docker-apisix-etcd-1 (2a92a0cefff9194fcd1dad4bdeabf4201d9047ec2633eda455c6e46528668af4): Bind for 0.0.0.0:2379 fa…

c++输入输出流和文件操作总结

目录 一、c的输入输出流——> 指的是字节流的数据传送;具有类型安全和可扩展性。 二、流的出入路径 三、c流类库 ①概览 ②标准输出流&#xff1a; ③标准输入流&#xff1a; 四、文件操作&#xff08;ascii文件和二进制文件&#xff09; 五、字符串流&#xff08;或称…

【力扣题解】P94-二叉树的中序遍历-Java题解

&#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【力扣题解】 文章目录 【力扣题解】P94-二叉树的中序遍历-Java题解&#x1f30f;题目描述&#x1f4a1;题解&#x1f30f…

oracle与mysql的分析函数(窗口函数)

分析函数定义 在SQL语句中&#xff0c;很多查询语句需要进行GROUP BY分组汇总&#xff0c;但是一旦经过分组&#xff0c;SELECT返回的记录数就会减少。为了保留所有原始行记录&#xff0c;并且仍可以进行分组数据分析&#xff0c;分析函数应运而生。 Oracle 8i 版本开始支持窗…

C++实现令牌桶过滤算法

什么是令牌桶算法 令牌桶算法通过限制令牌桶的固定容量&#xff0c;实现对资源以及流量的延迟控制。请求者需先获取令牌&#xff0c;方可执行动作。若令牌桶内具有足够令牌便可通过消耗相等数量放过请求&#xff1b;而若令牌不足&#xff0c;则会拒绝请求。 该算法具备平滑的…

C语言停车场模型详解

C语言停车场模型详解 1. 引言2. 代码概述3. 代码详解3.1 定义常量和数据结构3.2 初始化车库3.3 查找车辆所在车库3.4 查找车辆所在的车位3.5 打印车库状态3.6 打印等候车辆3.7 车辆入库3.8 车辆出库3.9 菜单功能3.10 主函数 5.效果展示5.完整代码6. 总结 1. 引言 本文将介绍一…

Android : 画布绘制矩形和文字 让其居中显示简单应用

示例图&#xff1a; CenterView.java package com.example.demo;import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.Log; import android.view.View;public class Center…

生成式 AI 原生开发

如何成为生成式AI原生开发者&#xff0c;快速进入&#xff1a; 下一站 GenAI QCon 上海站喊你上车啦&#xff01; 无限构建&#xff0c;成为生成式 AI 原生开发者&#xff0c;12 月 28 日&#xff0c;下一站 GenAI 巴士即将抵达 QCon 全球软件开发大会上海站&#xff0c;码…

人大女王金融硕士为何是在职金融人士提升自己的首选?一起来看看

在这个经济飞速发展的时代&#xff0c;职场竞争愈发激烈&#xff0c;如果一味的安于现状&#xff0c;那么很有可能被社会所淘汰。近年来&#xff0c;金融行业的发展更是迅速&#xff0c;对于高端人才的需求也越来越大。所以对于从事这行的工作者来说&#xff0c;在职研究生就是…

QML —— RadioButton的两个经典示例(附完整源码)

示例1-效果 示例2-效果 实例1 - 源码 import QtQuick 2.12 import QtQuick.Window 2.12import QtQuick.Layouts 1.12 import QtQuick.Controls 2.5Window {visible: truewidth: 640height: 480title: qsTr("Hello World")Text{id: classNametext: qsTr("--&quo…

金融贷款行业怎么精准获客,电销打吐了!教你两招

助贷行业&#xff0c;一般都会设有kpi&#xff0c;压力竞争都不小。虽然现在贷款电销大家对此意见不同&#xff0c;但是&#xff0c;不可否认&#xff0c;这个行业&#xff0c;电销就是它们最快速的获客方式。只要耐得住性子&#xff0c;有一份精准的话单&#xff0c;就可以开工…

在线教育系统源码解读:定制化企业培训APP的开发策略

当下&#xff0c;企业培训正经历着一场数字化的迭代&#xff0c;定制化企业培训APP应运而生&#xff0c;成为提升员工技能、推动企业发展的重要工具。下文小编将与大家一同深入了解在线教育系统的源码&#xff0c;探讨开发定制化企业培训APP的策略&#xff0c;以满足不同企业的…

AI大模型引领未来智慧科研暨ChatGPT在地学、GIS、气象、农业、生态、环境等领域中的高级应用

以ChatGPT、LLaMA、Gemini、DALLE、Midjourney、Stable Diffusion、星火大模型、文心一言、千问为代表AI大语言模型带来了新一波人工智能浪潮&#xff0c;可以面向科研选题、思维导图、数据清洗、统计分析、高级编程、代码调试、算法学习、论文检索、写作、翻译、润色、文献辅助…

yolov8 细胞分割数据集准备及训练

1、数据 下载:https://universe.roboflow.com/motherson-hm/5-part-diff 500来张,5个类别(嗜碱性细胞、嗜酸细胞、淋巴细胞、单核细胞、中性粒细胞) yolo 分割数据标注格式: 与检测类似,就是坐标分割有多个 2、训练 训练yaml: seg_data.yaml (与检测格式一样) …

代码随想录算法训练营day1|704.二分查找、27.移除元素

第一章 数组 part01 今日任务 数组理论基础&#xff0c;704. 二分查找&#xff0c;27. 移除元素 详细布置 数组理论基础 文章链接&#xff1a;代码随想录 题目建议&#xff1a; 了解一下数组基础&#xff0c;以及数组的内存空间地址&#xff0c;数组也没那么简单。 704. 二…

玩转安卓手机录屏,轻松掌握录屏技巧!

“安卓手机有录屏功能吗&#xff1f;新买了一部安卓手机&#xff0c;因为之前都是在用苹果手机&#xff0c;所以有点不习惯&#xff0c;最近需要用到录屏功能&#xff0c;但怎么都找不到&#xff0c;希望大家教教我&#xff0c;安卓手机怎么录屏&#xff1f;” 在现代社交媒体…

Redis中RDB和AOF

Redis中RDB和AOF 定时间间隔执行数据集的时间快照&#xff0c;把某一时刻数据和妆容以文件的形式写到磁盘上&#xff0c;也就是快照。 配置文件 如果是普通安装方式可以跳过&#xff0c;如果是docker安装&#xff0c;需要到官网下载redis.conf配置文件到本地&#xff0c;地址…