在这里插入图片描述

三三要成为安卓糕手

引入

Room是一个抽象层,对SQLite进行了封装,简化了SQLite数据库的操作,让开发者能以更加对象化的方式进行数据库操作;Room解决了SQLite操作繁琐,容易产生错误的问题,让开发者能以更加对象化的方式进行数据库操作。

一:添加依赖

Room属于Jetpack中关于数据库操作的库,不属于安卓原生SDK开发包,所以需要单独添加依赖

// app/build.gradle
dependencies {//添加room运行时依赖库implementation "androidx.room:room-runtime:2.6.1"// Room 编译时注解处理器annotationProcessor "androidx.room:room-compiler:2.6.1"// 可选:RxJava2 支持 (如果需要使用RxJava2的异步机制配合Room使用,需要添加这个依赖)implementation "androidx.room:room-rxjava2:2.6.1"// 可选:RxJava3 支持 (如果需要)implementation "androidx.room:room-rxjava3:2.6.1"
}

二:Room 的核心组件

Room 数据库主要有三个核心组件:

  • Entity(实体类):用于表示数据库表的数据结构。

  • DAO(Data Access Object):用于定义数据库操作的方法。

  • Database(数据库类):用于创建数据库实例,并将 Entity 和 DAO 关联起来

1:Entity层

定义与作用Entity 代表数据库中的一张表,它是一个 Java 类,通过 @Entity 注解来标识。每个 Entity 类的实例对应表中的一行数据,类中的属性对应表中的列

@Entity(tableName = "user-room")
public class MyUser {@PrimaryKey(autoGenerate = true)private int id;@ColumnInfo(name = "user_age")private int age;@ColumnInfo(name = "user_name")private String name;@ColumnInfo(name = "user_email")private String email;public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public int getId() {return id;}public void setId(int id) {this.id = id;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
  • Entity [ˈentəti] 实体

    理解:把注解转化成编译器能够看懂的东西

  • tableName = "user-room" 指定了该实体类对应的数据库表名为 user - room

  • @ColumnInfo(name = "user_age")当前的字段对应我们数据库中那一列的字段

  • @PrimaryKey(autoGenerate = true) 自增主键,设置为fasle的话就需要程序员自己设置id了

2:DAO层(数据访问对象)

定义与作用Dao 接口定义了对数据库进行增删改查(CRUD,Create、Read、Update、Delete)操作的方法。它是应用代码与数据库之间交互的桥梁,通过定义不同的方法来执行具体的 SQL 语句或 Room 封装的操作

@Dao
public interface MyUserDao {@Insertvoid insertUser(MyUser user);/*** 通过MyUser类型直接更新数据库,Room会根据MyUser中的主键来查找对应的数据,并且更新* @param user*/@Updateint updateUser(MyUser user);/*** 更新user-room这个表中,名字是等于name(第一个参数)的数据,把这条数据的user_age更新为age(第二个参数)*/@Query("update `user-room` set user_age = :age where user_name = :name")int updateUser(String name , int age);/*** 通过name查询user-room表中的某个数据* @param name* @return*/@Query("select * from `user-room` where user_name = :name")List<MyUser> getUserByName(String name);@Deleteint delUser(MyUser user);/*** 通过name删除对应的用户* @param name* @return*/@Query("delete from `user-room` where user_name = :name ")int delete(String name);
}
  • 这里设置的插入方法没有返回值;有返回值的情况:当插入单个实体对象时,返回值是一个 long 类型,表示插入数据后自动生成的主键值(前提是自增主键)

3:Database层

它是一个抽象类,通过 @Database 注解来标识,通常会包含一个或者多个抽象方法),用于返回定义好的 Dao 接口实例,Room 会在运行时自动生成该抽象类的实现;(可以简单理解成一个方法对应找库中的一个表table)

@Database(entities = {MyUser.class} , version = 1)
public abstract class MyUserDatabase extends RoomDatabase {public abstract MyUserDao userDao();static final Migration MIGRATION_1_2 = new Migration(1,2) {@Overridepublic void migrate(@NonNull SupportSQLiteDatabase supportSQLiteDatabase) {supportSQLiteDatabase.execSQL("alter table `user-room` add column user_email text");}};
}
  • entities = {MyUser.class}关联一张表的名字,可以关联多张table,在花括号中填写即可;前提这张表一定是被entity标注过的

(1)版本迁移

如果要实现从版本 1 迁移到版本 5,不能直接写 Migration(1, 5) 来 “一步到位” 完成所有中间版本(1→2→3→4→5)的迁移。Room 要求必须为每一个相邻的版本跨度都定义对应的 Migration,也就是需要分别定义:

  • 从版本 1 到版本 2 的 Migration
  • 从版本 2 到版本 3 的 Migration
  • 从版本 3 到版本 4 的 Migration
  • 从版本 4 到版本 5 的 Migration

然后在构建数据库时,通过 addMigrations() 方法把这些所有相邻版本的 Migration 都添加进去,Room 会在数据库升级时,按顺序执行这些 Migration,逐步完成从版本 1 到版本 5 的迁移。

(2)addMigration

        MyUserDatabase userDatabase = Room.databaseBuilder(ContentProviderActivity.this, MyUserDatabase.class, "user-database.db").addMigrations(MyUserDatabase.MIGRATION_1_2).build();

(3)数据库升级的时机

前提:创建数据库时add了对应的版本升级方法,这个迁移方法内部的具体规则需要再Database层中进行声明

如果当前版本为1,由于要给表添加新的列或者修改某个字段等等,想要升级到版本2;

那么这里就要修改为2@Database(entities = {MyUser.class} , version = 2),再次运行代码的时候,MyUserDatabase.MIGRATION_1_2 这个迁移规则,它会告诉 Room 如何将版本 1 的数据库转换为版本 2 的数据库,这样在数据库版本升级时,就能按照这个规则来执行相应的操作

    static final Migration MIGRATION_1_2 = new Migration(1,2) {@Overridepublic void migrate(@NonNull SupportSQLiteDatabase supportSQLiteDatabase) {supportSQLiteDatabase.execSQL("alter table `user-room` add column user_email text");}};

migration 信息迁移 alter 修改

效果如下,我们在Entity层中新增加的字段user_email成功添加进来了,现在就是版本2

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4:创建数据库

        MyUserDatabase userDatabase = Room.databaseBuilder(ContentProviderActivity.this, MyUserDatabase.class, "user-database.db").addMigrations(MyUserDatabase.MIGRATION_1_2).build();
  • 参数一:上下文
  • 参数二:数据库的class对象
  • 参数三:表示要创建的 SQLite 数据库文件的名称。

三:增删查改

1:增

    @Insertvoid insertUser(MyUser user);
        /*** 插入数据*/findViewById(R.id.btn_insert).setOnClickListener(view -> {new Thread(new Runnable() {@Overridepublic void run() {//可以理解成操作table表的对象MyUserDao myUserDao = userDatabase.userDao();MyUser user = new MyUser();user.setName(etUserName.getText().toString().trim());user.setAge(Integer.valueOf(etUserAge.getText().toString().trim()));myUserDao.insertUser(user);userDatabase.close();}}).start();});

数据库操作是一个非常耗时的操作,如果是在主线程操作会引起卡顿和崩溃,Room中插入数据需要指定在非主线程中进行,使用SQLite不用指定新线程,因为它内部已经帮我们处理好了外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(1)插入结果

Room数据库会把我们的插入或者查询操作进行分段读写,所以就有三个文件,没有db后缀,Room也会自动帮我们转化为db文件的

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为了测试,我们手动去添加后缀;并且想要整合三个文件,就需要手动close一次数据库操作

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

效果如下

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2:查 & 改

(1)修改数据

    /*** 通过MyUser类型直接更新数据库,Room会根据MyUser中的主键来查找对应的数据,并且更新* @param user*/@Updateint updateUser(MyUser user);
        /*** 更新数据*/findViewById(R.id.btn_update).setOnClickListener(view -> {new Thread(new Runnable() {@Overridepublic void run() {MyUserDao myUserDao = userDatabase.userDao();MyUser user = new MyUser();user.setId(1);user.setName(etUserName.getText().toString().trim());user.setAge(Integer.valueOf(etUserAge.getText().toString().trim()));myUserDao.updateUser(user);//通过名字查询到对应的信息,修改这个用户的年龄userDatabase.userDao().updateUser("lisi",100);}}).start();});

(2)根据主键查找

    /*** 通过name查询user-room表中的某个数据* @param name* @return*/@Query("select * from `user-room` where user_name = :name")List<MyUser> getUserByName(String name);
        /*** 查询数据*/findViewById(R.id.btn_select).setOnClickListener(view -> {new Thread(new Runnable() {@Overridepublic void run() {MyUserDao myUserDao = userDatabase.userDao();String queryName = etUserName.getText().toString().trim();List<MyUser> users = myUserDao.getUserByName(queryName);Log.i(TAG, "run:users.size" + users.size());if(users.size() > 0){runOnUiThread(new Runnable() {@Overridepublic void run() {//显示查询到的用户数据MyUser user = users.get(0);tvMessage.setText(tvMessage.getText() +"\n" + user.getName() + ":" + user.getAge());}});}}}).start();});

效果如下

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(3)根据字段查找

通过别的数据进行user的查找;不想通过User实体类和主键,进行查找

自定义查询规则,sql语句

    /*** 更新user-room这个表中,名字是等于name(第一个参数)的数据,把这条数据的user_age更新为age(第二个参数)*/@Query("update `user-room` set user_age = :age where user_name = :name")int updateUser(String name , int age);

3:删

多尝试

    @Deleteint delUser(MyUser user);
    /*** 通过name删除对应的用户* @param name* @return*/@Query("delete from `user-room` where user_name = :name ")int delete(String name);
        findViewById(R.id.btn_delete).setOnClickListener(view -> {new Thread(new Runnable() {@Overridepublic void run() {
//                    MyUser user = new MyUser();
//                    user.setId(1);
//                    userDatabase.userDao().delUser(user);userDatabase.userDao().delete("wangwu");}}).start();});

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

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

相关文章

Next.js 介绍:为什么选择它来构建你的下一个 Web 应用?

Next.js 介绍&#xff1a;为什么选择它来构建你的下一个 Web 应用&#xff1f; 作者&#xff1a;码力无边你好&#xff0c;欢迎来到我们的 Next.js 专栏&#xff01;在接下来的 30 篇文章中&#xff0c;我们将一起踏上一段从入门到精通的旅程&#xff0c;深入探索这个强大而优雅…

开发环境 之 编辑器、编译器、IDE梳理

小生第一次学习编程时&#xff0c;懵懵搞不懂编辑器、编译器、IDE区别&#xff0c;虽然这对前期学习编程语言语法的影响不是很大&#xff0c;但是现在梳理一下&#xff0c;总归心里踏实些。 一、概念及区别 IDE是前面几者的集成&#xff0c;前面几个分别是IDE的子集。对比维度编…

高级RAG策略学习(六)——Contextual Chunk Headers(CCH)技术

Contextual Chunk Headers&#xff08;CCH&#xff09;技术深度解析 第一部分&#xff1a;理论基础与核心原理 一、核心定义&#xff1a;给 “文本块” 加 “上下文标签” Contextual Chunk Headers&#xff08;上下文块标题&#xff0c;简称 CCH&#xff09;本质是为文档拆分后…

人形机器人控制系统核心芯片从SoC到ASIC的进化路径

目录&#xff1a; 0 前言 1 人形机器人控制系统核心芯片选择ASIC而非SoC的理由 1.1 SoC的架构特征 1.2 ASIC的架构特征 1.3 SoC的优势&#xff08;继承软件生态&#xff09; 1.4 ASIC的优势&#xff08;硬件底层算法就是应用层算法&#xff09; 1.5 人形机器人控制系统核…

linux thread 线程一

thread线程是linux的重要概念。线程不能独立存在&#xff0c;必须在进程中存在。一个进程必须有一个线程&#xff0c;如果进程中没有创建新线程&#xff0c;进程启动后本身就有一个线程。使用getpid、getppid获取进程的进程ID和父进程ID。使用pthread_self获取到当前线程的ID。…

Arduino Nano33 BLESense Rev2【室内空气质量检测语音识别蓝牙调光台灯】

一、硬件介绍 1、产品特点 Arduino Nano 33 BLE Rev2&#xff0c;利用了nRF52840微控制器的先进功能。这款32位Arm Cortex-M4 CPU 64 MHz与MicroPython的兼容性增强了板子的灵活性&#xff0c;该开发板的突出特点是其蓝牙低功耗&#xff08;BLE&#xff09;功能&#xff0c;使…

【问题解决】mac笔记本遇到鼠标无法点击键盘可响应处理办法?(Command+Option+P+R)

背景 如题。鼠标无法点击&#xff0c;但可以移动。触控板能够波动&#xff0c;鼠标翻页能够work&#xff0c;但是点击后无法响应。 根因 电脑缓存问题 解决办法 重置PRAM&#xff1a; 确保电脑关机状态&#xff08;可以先sudo shutdown -t now)&#xff08;一定要确保&#xff…

23ai数据库通过SQLcl生成AWR报告

‌1. 查看现有快照SQL> awr list snap;SNAP_ID DBID BEGIN_INTERVAL_TIME END_INTERVAL_TIME FLUSH_LEVEL __________ _____________ __________________________________ __________________________________ ______________793 …

基于Django+Vue3+YOLO的智能气象检测系统

基于DjangoVue3YOLO的智能气象检测系统 项目简介 本项目是一个集成了人工智能深度学习技术的现代化气象检测系统&#xff0c;采用前后端分离架构&#xff0c;结合YOLO目标检测算法&#xff0c;实现了对气象现象的智能识别与分析。系统提供了完整的用户管理、实时检测、历史记录…

(4)什么时候引入Seata‘‘

非常好的问题&#xff01;这两个问题正是技术选型时需要重点考虑的。什么时候需要引入 Seata&#xff1f;需要引入 Seata 的场景&#xff1a;跨数据库的分布式事务// 订单服务&#xff08;MySQL&#xff09; 库存服务&#xff08;PostgreSQL&#xff09; 账户服务&#xff08…

苹果内部 AI聊天机器人“Asa”曝光,为零售员工打造专属A

MacRumors网站的亚伦佩里斯&#xff08;Aaron Perris&#xff09;透露&#xff0c;苹果正在内部测试一款名为“Asa”的AI聊天机器人。这款工具旨在赋能Apple Store零售员工&#xff0c;帮助他们快速掌握iPhone等产品的特色和差异化使用场景&#xff0c;从而提升与顾客互动时的解…

MySQL常见报错分析及解决方案总结(12)---slave_net_timeout

关于超时报错&#xff0c;一共有五种超时参数&#xff0c;详见&#xff1a;MySQL常见报错分析及解决方案总结(7)---超时参数connect_timeout、interactive_timeout/wait_timeout、lock_wait_timeout、net等-CSDN博客 以下是当前报错的排查方法和解决方案&#xff1a; 在 Wind…

云计算学习笔记——日志、SELinux、FTP、systemd篇

《云计算学习日记Day15》—— 从零开始的云计算之旅 今天是系统学习云计算的第十五天&#xff0c;记录了关于我的云计算学习&#xff0c;后续将每日更新我的笔记。欢迎大家一起来学习&#xff0c;如果内容有遗漏和错误&#xff0c;还请大家多多指正和包涵&#xff0c;谢谢大家 …

3Ds Max Gamma值完全指南:问题识别与正确设置解析

当渲染图像与本地图片相比亮度偏黑或偏白时&#xff0c;很可能是因为Gamma输入输出设置不一致。需要注意的是&#xff0c;Gamma问题通常表现为整体亮度偏差&#xff0c;而非大面积曝光或全黑状况。Gamma设置教程问题一&#xff1a;Gamma校正未开启如果使用VR帧缓冲窗口渲染但未…

用 Rust + Actix-Web 打造“Hello, WebSocket!”——从握手到回声,只需 50 行代码

用 Rust Actix-Web 打造“Hello, WebSocket!”——从握手到回声&#xff0c;只需 50 行代码 一、为什么选择 Rust 写 WebSocket&#xff1f; 零成本抽象&#xff1a;编译期确定生命周期&#xff0c;无 GC 抖动&#xff0c;延迟低至微秒级actix-web&#xff1a;Tokio 生态最成熟…

基于Cursor的 STM32工程搭建 (编译、下载、仿真)

嵌入式学习交流Q群 679912988 简介 本工程使用GCC编译器、MinGW、CMake构建工具和OpenOCD调试工具。实现了替代KEIL, IAR等在某些情况下不方便使用的情况。实现了编译、调试、下载、烧录一体。搭配Cursor的Tab补全功能&#xff0c;编码效率大大提升。 工具下载及安装 Cursor…

数据量太大处理不了?Hadoop+Spark轻松解决海洋气象大数据分析难题

&#x1f34a;作者&#xff1a;计算机毕设匠心工作室 &#x1f34a;简介&#xff1a;毕业后就一直专业从事计算机软件程序开发&#xff0c;至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长&#xff1a;按照需求定制化开发项目…

Day34 UDP套接字编程 可靠文件传输与实时双向聊天系统

day34 UDP套接字编程 可靠文件传输与实时双向聊天系统 UDP文件传输 实现客户端向服务器传输文件&#xff08;如图片&#xff09;的功能&#xff0c;确保传输后文件内容完全一致且可正常打开。传输过程采用简单的确认机制防止数据包丢失&#xff0c;传输完成后双方程序自动退出。…

策略模式-不同的鸭子的案例

介绍了策略模式在C#中的应用&#xff0c;以一个鸭子的例子来说明。首先定义了鸭子类以及鸭子的行为&#xff08;方法&#xff09;&#xff0c;然后通过继承和实现接口的方式来定义不同种类的鸭子的特性。介绍了策略模式的概念&#xff0c;将相同的算法封装在不同的类中&#xf…

C++语言编程规范-初始化和类型转换

01 C语言编程规范-常量 02 初始化和类型转换 声明、定义与初始化 03 禁止用 memcpy、memset 初始化非 POD 对象 说明&#xff1a;POD 全称是“Plain Old Data”&#xff0c;是 C 98 标准(ISO/IEC 14882, first edition, 1998-09-01)中引入的一个概念&#xff0c; PO…