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

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 注解中设置 exportSchematrue

        在你的数据库类的 @Database 注解中,将 exportSchema 设置为 true

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


http://www.kler.cn/a/315353.html

相关文章:

  • 网络基础Linux
  • React中 修改 html字符串 中某些元素的属性
  • 【常见问题解答】远程桌面无法复制粘贴的解决方法
  • Python高级编程模式和设计模式
  • 阿里云通义大模型团队开源Qwen2.5-Coder:AI编程新纪元
  • Ceph 中Crush 算法的理解
  • 【MySQL 03】表的操作
  • mpls 动态LSP的标签发布协议
  • TCP/IP - IP
  • 鸿蒙NEXT生态应用核心技术理念:统一生态,原生智能
  • web自动化学习笔记
  • K8s 之控制器的定义及详细调用案例
  • SpringBoot 整合 Caffeine 实现本地缓存
  • UDP_SOCKET编程实现
  • 行阶梯形矩阵的定义,通过正例和反例说明如何判断一个矩阵是不是行阶梯形矩阵
  • 9月22日,每日信息差
  • 基于python+django+mysql+Nanodet检测模型的水稻虫害检测系统
  • 基于Python+SQLite的课程管理系统
  • Spring boot中常用注解解释
  • 汽车焊机数据通信:Profinet转Canopen网关的神奇连接
  • 新160个crackme - 062-syllogism-crackme1
  • GlusterFS 分布式文件系统
  • 初识 performance_schema:轻松掌握MySQL性能监控
  • 基于深度学习的因果关系建模
  • [论文笔记]MRRNET
  • 树和二叉树的概念以及结构