Google 官方数据库框架Room使用教程
Room 是 Google 提供的官方 ORM 框架,用于处理 Android 应用中的 SQLite 数据库操作。它是 Android Jetpack 的一部分,具有编译时检查、数据持久化的简化操作以及与 LiveData 和 RxJava 的良好集成。
以下是 Room 的详细使用教程,结合rxjava,并将其封装在 DatabaseHelper
中进行管理,同时处理数据库升级。
1. 添加依赖
首先,在 build.gradle
文件中添加 Room 和 RxJava 的依赖:
dependencies {
def room_version = "2.6.1"
// Room 依赖
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
// Room 支持 RxJava
implementation "androidx.room:room-rxjava3:$room_version"
}
2. 创建实体类
Room 使用实体类来表示数据库中的表。每个实体类都对应一个数据库表,类的每个字段对应数据库表中的列。
@Entity(tableName = "users")
public class User {
@PrimaryKey(autoGenerate = true)
private int id;
private String name;
private int age;
// Getters 和 Setters
}
重要注解:
@Entity
:声明一个实体类,并指定表名。@PrimaryKey
:指定主键,autoGenerate = true
表示主键自动增长。每个 Room 实体都必须定义一个主键,用于唯一标识相应数据库表中的每一行@ColumnInfo
:用于指定列的名称(可选)。
3. 创建 DAO(数据访问对象)接口并集成 RxJava
DAO 是用来定义访问数据库的方法的接口。每个 DAO 都是一个接口,里面包含了数据库的查询、插入、删除和更新方法。
@Dao
public interface UserDao {
// 查询所有用户,返回 Flowable 以便数据发生变化时自动通知观察者
@Query("SELECT * FROM users")
Flowable<List<User>> getAllUsers();
// 根据 ID 获取用户
@Query("SELECT * FROM users WHERE id = :userId")
Single<User> getUserById(int userId);
// 插入用户,使用 Completable 来处理异步插入操作
@Insert
Completable insertUser(User user);
// 更新用户信息
@Update
Completable updateUser(User user);
// 删除单个用户
@Delete
Completable deleteUser(User user);
// 删除所有用户
@Query("DELETE FROM users")
Completable deleteAllUsers();
}
重要注解:
@Dao
:定义 DAO 类。@Query
:用于定义 SQL 查询。@Insert
:用于插入数据。@Update
:用于更新数据。@Delete
:用于删除数据。
4. 创建 RoomDatabase 类
RoomDatabase
类是用于创建数据库并关联 DAO 的抽象类。它是 Room 框架的核心部分。
@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
重要注解:
@Database
:用于指定实体类和数据库版本。RoomDatabase
:通过继承该类,创建数据库实例。
5.封装 DatabaseHelper
将 Room 封装成一个简单易用的 DatabaseHelper
,我们可以通过创建一个单例类来管理 Room 数据库的实例和 DAO 的操作。这样做可以避免在多个地方重复初始化数据库,同时也能简化对 DAO 的调用。
public class DatabaseHelper {
private static DatabaseHelper instance;
private final AppDatabase database;
private DatabaseHelper(Context context) {
database = Room.databaseBuilder(context.getApplicationContext(),
AppDatabase.class, "my_database")
// .fallbackToDestructiveMigration()// 如果没有迁移策略,销毁并重新创建
.build();
}
public static synchronized DatabaseHelper getInstance(Context context) {
if (instance == null) {
instance = new DatabaseHelper(context);
}
return instance;
}
public UserDao getUserDao() {
return database.userDao();
}
// 插入用户数据,返回 Completable
public Completable insertUser(User user) {
return getUserDao().insertUser(user)
.subscribeOn(Schedulers.io()) // 在 IO 线程执行
.observeOn(AndroidSchedulers.mainThread()); // 在主线程观察
}
// 查询所有用户,返回 Flowable,数据变更时通知观察者
public Flowable<List<User>> getAllUsers() {
return getUserDao().getAllUsers()
.subscribeOn(Schedulers.io()) // 在 IO 线程查询
.observeOn(AndroidSchedulers.mainThread()); // 在主线程观察
}
// 删除所有用户,返回 Completable
public Completable deleteAllUsers() {
return getUserDao().deleteAllUsers()
.subscribeOn(Schedulers.io()) // 在 IO 线程执行
.observeOn(AndroidSchedulers.mainThread()); // 在主线程观察
}
}
注意:Room 数据库每次数据库结构发生变化(如添加、删除或修改表或字段)时更新数据库版本,并且需要定义迁移策略来确保数据的正确迁移,如果没有提供迁移策略,Room 会抛出异常。fallbackToDestructiveMigration
()的作用是在没有可用的迁移策略时,Room 直接删除旧的数据库文件,并重新创建一个新的数据库(包含新版本的数据库结构),但是 所有的旧数据都会丢失。
6. 数据库迁移
如果你对数据库结构进行修改(如添加字段),需要执行数据库迁移,避免数据丢失。Room 提供了 Migration
类用于管理数据库版本的升级。如当新增加一个Book表:
6.1. 创建新的实体类 Book
import androidx.room.Entity;
import androidx.room.PrimaryKey;
@Entity(tableName = "books")
public class Book {
@PrimaryKey(autoGenerate = true)
public int id;
public String title;
public String author;
public Book(String title, String author) {
this.title = title;
this.author = author;
}
// Getters and Setters (根据需要生成)
}
6.2. 创建 BookDao
接口
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Update;
import androidx.room.Delete;
import java.util.List;
import io.reactivex.Completable;
import io.reactivex.Flowable;
import io.reactivex.Single;
@Dao
public interface BookDao {
// 插入书籍
@Insert
Completable insertBook(Book book);
// 获取所有书籍
@Query("SELECT * FROM books")
Flowable<List<Book>> getAllBooks();
// 根据 ID 获取书籍
@Query("SELECT * FROM books WHERE id = :bookId")
Single<Book> getBookById(int bookId);
// 更新书籍
@Update
Completable updateBook(Book book);
// 删除书籍
@Delete
Completable deleteBook(Book book);
}
6.3.更新 AppDatabase
类并添加迁移逻辑
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
@Database(entities = {User.class, Book.class}, version = 2) // 更新版本号
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
public abstract BookDao bookDao();// 添加 BookDao
private static volatile AppDatabase INSTANCE;
public static AppDatabase getInstance(Context context) {
if (INSTANCE == null) {
synchronized (AppDatabase.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
AppDatabase.class, "my_database")
.addMigrations(MIGRATION_1_2) // 添加迁移策略
.build();
}
}
}
return INSTANCE;
}
// 定义迁移策略:从版本 1 升级到版本 2
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(SupportSQLiteDatabase database) {
// 创建新表 Book
database.execSQL("CREATE TABLE IF NOT EXISTS `books` (" +
"`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
"`title` TEXT, " +
"`author` TEXT)");
}
};
}
7、多次迁移情况
如果你有多个版本的数据库更新,例如从版本 1 升级到 2,之后再升级到 3,每次升级都需要定义相应的迁移策略。
static final Migration MIGRATION_2_3 = new Migration(2, 3) {
@Override
public void migrate(SupportSQLiteDatabase database) {
// 例如,在版本 3 中新增字段
database.execSQL("ALTER TABLE users ADD COLUMN last_login INTEGER");
}
};
// 添加多个迁移
Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "user_database")
.addMigrations(MIGRATION_1_2, MIGRATION_2_3)
.build();
8.导出架构
Room 可以在编译时将数据库的架构信息导出为 JSON 文件,为了帮助开发者在开发和维护过程中了解数据库的结构,当数据库结构发生变化时(如添加了新表、列或修改了数据类型),可以通过 JSON 文件查看这些变化。
8.1如何导出架构信息
要启用 Room 的 schema 导出功能,你需要在 build.gradle
文件中配置 room.schemaLocation
选项,并设置 exportSchema
属性。
-
配置
room.schemaLocation
:在build.gradle
文件中配置room.schemaLocation
,指定导出 JSON 文件的目录。
在 app
模块的 build.gradle
文件中添加以下配置:
android {
// 其他配置...
defaultConfig {
// 其他默认配置...
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation": "$projectDir/schemas"]
}
}
}
}
-
设置
exportSchema
:在实体类的@Database
注解中设置exportSchema
为true
在你的数据库类的 @Database
注解中,将 exportSchema
设置为 true
:
@Database(entities = {User.class}, version = 1,exportSchema = true)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}