当前位置: 首页 > news >正文

Android学习总结之Room篇

一、Room 框架基础

1. 实体类(Entity)

实体类用于描述数据库表的结构。通过使用 @Entity 注解,可以将一个 Java 类映射到数据库中的一张表。例如,以下是一个简单的 User 实体类:

import androidx.room.Entity;
import androidx.room.PrimaryKey;@Entity
public class User {@PrimaryKey(autoGenerate = true)public int id;public String name;public int age;
}

在这个例子中,@Entity 注解将 User 类标记为数据库实体,@PrimaryKey 注解指定了 id 字段为主键,并且 autoGenerate = true 表示主键将自动生成。

2. 数据访问对象(DAO)

DAO 接口定义了对数据库的操作方法。通过使用 @Query@Insert@Update 和 @Delete 等注解,可以方便地执行 SQL 查询和数据的增删改操作。以下是一个简单的 UserDao 接口示例:

import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.Query;import java.util.List;@Dao
public interface UserDao {@Insertvoid insertUser(User user);@Query("SELECT * FROM User")List<User> getAllUsers();
}

在这个例子中,@Insert 注解用于插入数据,@Query 注解用于执行 SQL 查询语句。

3. 数据库类(Database)

数据库类负责创建和管理数据库实例。通过继承 RoomDatabase 类,并使用 @Database 注解指定实体类和数据库版本,可以创建一个 Room 数据库。以下是一个简单的 AppDatabase 类示例:

import androidx.room.Database;
import androidx.room.RoomDatabase;@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {public abstract UserDao userDao();
}

在这个例子中,@Database 注解指定了 User 类为数据库实体,版本号为 1。userDao() 方法用于获取 UserDao 实例。

二、Room 中实现 Entity 嵌套 Entity 创建相应的表

1. 定义相关实体类

假设我们有一个Author(作者)实体类和一个Book(书籍)实体类,每一个Author可以有多本Book,我们希望在查询Author时能同时获取其相关的Book信息。

Author实体类
import androidx.room.Entity;
import androidx.room.PrimaryKey;
import java.util.List;@Entity
public class Author {@PrimaryKeypublic int id;public String name;// 这里的books是与该作者相关的书籍列表,在后续会通过@Relation注解关联public List<Book> books;
}
Book实体类
import androidx.room.Entity;
import androidx.room.ForeignKey;
import androidx.room.PrimaryKey;@Entity(foreignKeys = @ForeignKey(entity = Author.class,parentColumns = "id",childColumns = "authorId"))
public class Book {@PrimaryKeypublic int id;public String title;// 关联作者的idpublic int authorId;
}

2. 定义包含关系的 POJO(Plain Old Java Object)类

为了更好地处理嵌套关系,我们创建一个 POJO 类,用于将Author和其相关的Book进行组合。

import androidx.room.Embedded;
import androidx.room.Relation;
import java.util.List;public class AuthorWithBooks {// 将Author实体类嵌入到AuthorWithBooks中@Embeddedpublic Author author;// 通过外键关联,获取与该作者相关的书籍列表@Relation(parentColumn = "id",entityColumn = "authorId")public List<Book> books;
}

在上述代码中:

  • @Embedded注解用于将一个实体类嵌入到另一个类中,这里将Author实体嵌入到AuthorWithBooks中。
  • @Relation注解用于定义两个实体之间的关系,parentColumn指定父实体(这里是Author)的列,entityColumn指定子实体(这里是Book)的列,通过这两个列的关联来获取相关数据。

3. 定义数据访问对象(DAO)接口

在 DAO 接口中定义查询方法,用于获取AuthorWithBooks数据。

import androidx.room.Dao;
import androidx.room.Query;import java.util.List;@Dao
public interface AuthorDao {@Query("SELECT * FROM Author")List<AuthorWithBooks> getAuthorsWithBooks();
}

这里的查询语句只是简单地从Author表中查询数据,Room 会根据AuthorWithBooks类中的关系注解,自动关联并获取相关的Book数据。

4. 定义 Room 数据库类

import androidx.room.Database;
import androidx.room.RoomDatabase;@Database(entities = {Author.class, Book.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {public abstract AuthorDao authorDao();
}

5. 使用示例

import androidx.room.Room;public class MainActivity {public static void main(String[] args) {AppDatabase db = Room.databaseBuilder(, AppDatabase.class, "my - database").build();AuthorDao authorDao = db.authorDao();List<AuthorWithBooks> authorsWithBooks = authorDao.getAuthorsWithBooks();for (AuthorWithBooks authorWithBooks : authorsWithBooks) {System.out.println("作者:" + authorWithBooks.author.name);for (Book book : authorWithBooks.books) {System.out.println("    书籍:" + book.title);}}}
}

三、Room的多表查询

1. 多表查询 SQL 语句示例(以常见的 MySQL 为例,假设存在学生表 students、课程表 courses、成绩表 scores)

假设 students 表有字段 id(学生编号)、name(学生姓名);courses 表有字段 id(课程编号)、course_name(课程名称);scores 表有字段 id(成绩记录编号)、student_id(关联学生表的学生编号)、course_id(关联课程表的课程编号)、score(成绩) 。

要查询每个学生的姓名、所选课程名称以及对应的成绩,SQL 语句如下:

SELECT s.name,c.course_name,sc.score
FROM students s
-- 使用INNER JOIN(内连接)关联成绩表scores
JOIN scores sc ON s.id = sc.student_id
-- 使用INNER JOIN关联课程表courses
JOIN courses c ON sc.course_id = c.id;

解释:

  • SELECT 子句指定要查询的列,这里选择学生姓名 s.name、课程名称 c.course_name 和成绩 sc.score
  • FROM 子句指定主表,这里以 students 表为主表,起别名 s
  • JOIN 用于连接其他表,ON 子句指定连接条件。第一个 JOIN 将 students 表和 scores 表通过学生编号关联起来;第二个 JOIN 将 scores 表和 courses 表通过课程编号关联起来,从而实现多表数据的联合查询。

2. 使用 Room(Android 中的数据库框架)实现类似多表查询

首先,定义相关的实体类:

  • 学生实体类 Student
import androidx.room.Entity;
import androidx.room.PrimaryKey;@Entity
public class Student {@PrimaryKeypublic int id;public String name;
}
  • 课程实体类 Course
import androidx.room.Entity;
import androidx.room.PrimaryKey;@Entity
public class Course {@PrimaryKeypublic int id;public String course_name;
}
  • 成绩实体类 Score
import androidx.room.Entity;
import androidx.room.ForeignKey;
import androidx.room.PrimaryKey;@Entity(foreignKeys = {@ForeignKey(entity = Student.class, parentColumns = "id", childColumns = "student_id"),@ForeignKey(entity = Course.class, parentColumns = "id", childColumns = "course_id")
})
public class Score {@PrimaryKeypublic int id;public int student_id;public int course_id;public int score;
}

然后,定义数据访问对象(DAO)接口,在其中定义查询方法:

import androidx.room.Dao;
import androidx.room.Query;import java.util.List;@Dao
public interface ScoreDao {@Query("SELECT s.name, c.course_name, sc.score " +"FROM Student s " +"JOIN Score sc ON s.id = sc.student_id " +"JOIN Course c ON sc.course_id = c.id")List<Object[]> getStudentCourseScore();
}

这里的 @Query 注解中写的 SQL 语句和前面纯 SQL 的多表查询思路一致。由于查询结果涉及多个表的不同列,返回类型定义为 List<Object[]>,每一个 Object[] 数组代表一条查询结果记录,数组中的元素依次对应查询的列(学生姓名、课程名称、成绩) 。

在使用时,通过 Room 数据库实例获取 ScoreDao 的实例并调用该查询方法:

import androidx.room.Room;public class MainActivity {public static void main(String[] args) {AppDatabase db = Room.databaseBuilder(, AppDatabase.class, "my - database").build();ScoreDao scoreDao = db.scoreDao();List<Object[]> result = scoreDao.getStudentCourseScore();for (Object[] row : result) {String studentName = (String) row[0];String courseName = (String) row[1];int studentScore = (int) row[2];System.out.println("学生:" + studentName + ",课程:" + courseName + ",成绩:" + studentScore);}}
}

四、Room 与直接使用 SQLite 的区别

易用性

  • Room:作为 Google 官方提供的在 Android 平台上操作数据库的抽象层框架,它对 SQLite 进行了封装,使用起来更加简洁和直观。例如,定义实体类时,只需使用注解(如@Entity@PrimaryKey等)来标识表结构和主键等信息,无需手动编写复杂的建表 SQL 语句;在数据访问对象(DAO)中,通过@Query注解编写 SQL 语句,或者使用框架提供的一些内置方法(如insertupdatedelete等)来操作数据库,大大简化了开发流程。
  • SQLite:直接使用 SQLite 时,需要开发者手动编写各种 SQL 语句来完成建表、插入、查询、更新和删除等操作,例如创建表时要完整地编写CREATE TABLE语句,包含列名、数据类型、约束条件等,相对来说对开发者的 SQL 知识要求较高,代码编写也更为繁琐。

代码结构

  • Room:有助于构建清晰、可维护的代码结构。它将数据库操作相关的代码划分为实体类(Entity)、数据访问对象(DAO)和数据库类(Database)。实体类用于描述数据库表中的数据结构,DAO 接口定义了对数据库的操作方法,数据库类则负责创建和管理数据库实例。这种分层的设计使得代码职责明确,易于理解和维护,符合现代 Android 开发的架构规范。
  • SQLite:直接使用 SQLite 时,代码结构相对较为松散,开发者可能会将 SQL 语句分散在不同的业务逻辑代码中,随着项目的增大,代码的可读性和可维护性会逐渐降低,难以快速定位和修改数据库相关的代码。

功能特性

  • Room:提供了许多实用的功能特性。比如,支持数据库版本管理,当数据库结构发生变化时,可以方便地进行版本升级,并在升级过程中执行相应的迁移操作;还支持关系映射,通过@Relation注解可以方便地处理表与表之间的关联关系,实现多表查询和数据的嵌套加载,如在一个实体类中嵌套另一个实体类的集合。
  • SQLite:本身是一个轻量级的数据库引擎,仅提供基本的数据库操作功能,对于数据库版本管理和复杂的关系映射等功能,需要开发者自行编写大量的代码来实现,增加了开发的难度和工作量。

性能

  • Room:虽然对 SQLite 进行了封装,但在执行 SQL 语句时,底层仍然是通过 SQLite 来实现的,因此在性能上不会有太大的损耗。同时,Room 还会对一些常见的操作进行优化,例如在批量插入数据时,会采用合适的方式来提高插入效率。不过,由于 Room 需要进行一些额外的处理(如注解处理、对象映射等),在某些极端情况下,可能会有轻微的性能开销。
  • SQLite:由于直接操作数据库,没有中间层的额外处理,在一些对性能要求极高、对代码执行效率非常敏感的场景下,直接使用 SQLite 可能会具有一定的性能优势,可以根据具体需求进行更精细的性能优化。

安全性

  • Room:在一定程度上增强了数据库操作的安全性。例如,在执行 SQL 语句时,Room 会对输入参数进行检查和处理,避免 SQL 注入等安全问题。通过使用类型安全的方法和参数绑定,减少了因错误的 SQL 语句导致的数据泄露或损坏的风险。
  • SQLite:直接使用 SQLite 时,如果开发者在编写 SQL 语句时不注意对输入参数的处理,很容易出现 SQL 注入漏洞,攻击者可以通过构造恶意的 SQL 语句来获取敏感数据或破坏数据库,安全性相对较低,需要开发者具备较强的安全意识和编写安全代码的能力。

五、总结

        Room 框架为 Android 开发者提供了一种更加优雅、高效的数据库操作方式。通过使用注解和分层设计,它简化了数据库操作的代码编写,提高了代码的可读性和可维护性。

相关文章:

  • 发送网络请求
  • 《无尽的尽头》今日开播 刘家祎大胆演绎林磊儿的“另一面”
  • RAG(检索增强生成)技术详解与应用实践:从原理到落地
  • 简单几步,开启 Intel VT-x 让电脑“解开CPU封印”
  • 蓝桥杯 20. 压缩变换
  • 数据分析之 商品价格分层之添加价格带
  • 欧姆龙NJ系列PLC通讯
  • vue3-springboot-mysql的docker部署
  • 怎么实现RAG检索相似文档排序:similarities
  • 云蝠智能大模型呼叫:AI驱动的通信服务革新与实践
  • 操作系统---进程同步与互斥
  • 【频谱分析仪与信号分析仪】异同比较
  • Unity后处理全解析:从入门到优化
  • 《Linux程序设计》实验8 线程程序设计
  • vulkanscenegraph显示倾斜模型(6)-帧循环
  • RTS 如何使用流控方式自动实现收发
  • 【每天一个知识点】熵(Entropy)
  • SpringBoot入门实战(项目搭建、配置、功能接口实现等一篇通关)
  • 【KWDB 创作者计划】_上位机知识篇---Github
  • 什么是公链?公链项目有哪些?公链项目开发
  • 韩国京畿道骊州市市长率团访问菏泽:想和菏泽一起办牡丹节
  • 安徽一交通事故责任认定引质疑:民警和司法鉴定人被处罚,已中止诉讼
  • 影子调查丨掉落的喷淋头:太原一7天酒店加盟店消防设施造假迷局
  • 最高法:侵犯著作权罪中的“复制发行”不包括单纯发行行为
  • 云南昭通黄吉庆寻子29年终团聚:儿子在同事鼓励下回乡认亲
  • 著名文学评论家、清华大学中文系教授蓝棣之逝世