认识Room数据库

认识Room数据库

1.ROOM数据库是什么

​ ROOM是Google为Android平台推出的一款数据库持久化库,它基于SQLite之上构建,旨在为开发者提供一种更高效、安全和简洁的方式来管理本地数据库。

​ ROOM是Android Jetpack的一个架构组件,它通过注解(Annotations)方式简化了数据库表的创建、数据查询和操作。

​ 其作为SQLite之上的抽象层,简化了数据库设置和配置以及交互方面的操作。

2.ROOM数据库原理

​ ROOM数据库的设计理念和 JavaWeb 的数据库操作在分层结构和实体映射上有相似性。

​ ROOM数据库的核心由Entity(实体),DAO(数据库访问对象),Database(数据库类)组成

img

1.Entity

​ ROOM使用编译时注解处理器,解析实体类并生成对应的表定义和列映射代码,将实体类的每个字段映射到对应表的列,当类被注解标记为实体时,其中的所有字段都将被持久化,除非通过别的注解忽略该字段,例如Ignore。

8c9f1659ee82ca43.png

@Entity(tableName = "user_table")
public class User {

    @PrimaryKey(autoGenerate = true)
    private int id;

    @ColumnInfo(name = "user_name")
    private String name;

    @ColumnInfo(name = "user_age")
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}

这是一个实体类的示例

其中@Entity(tableName = "user_table")这个注解代表将以下User类标记为一个实体并且对应映射表名为user_table。

User类中声明了id,name,age三个变量

@PrimaryKey(autoGenerate = true)表示将id标记为主键,同时autoGenerate=true的操作表示让数据库自动为id这列赋值,默认为自增主键。

@ColumnInfo(name = "user_age")表示将age变量对应的列名名称自定义为user_age,同时ColumInfo还支持为字段创建索引的功能。

需要注意的是ROOM设置主键时,必须有一个对应的setter方法

public void setId(int id) {
        this.id = id;
    }

2.DAO

​ 用于提供和数据库交互的接口,定义数据的增删改查操作。ROOM根据DAO的注解,在编译时解析方法并生成底层的SQL操作,同时验证SQL查询的合法性和字段匹配问题。Room 使用动态代理为 DAO 接口生成实现类,在运行时处理方法调用。

8b91b8bbd7256a63.png

@Dao
public interface UserDao {

    @Insert
    void insertUser(User user);

    @Update
    void updateUser(User user);

    @Delete
    void deleteUser(User user);

    @Query("SELECT * FROM user_table ORDER BY user_name ASC")
    LiveData<List<User>> getAllUsers();

    @Query("SELECT * FROM user_table WHERE id = :userId LIMIT 1")
    User getUserById(int userId);
}

这是一个DAO类的示例,@DAO将以下接口标记为DAO,标记的可以使接口也可以是抽象类。

接口中的注解分别将下面的方法标记为不同的数据库操作。

@Query注解提供了使用自定义SQL查询语句的方法,其中:userId作为占位符,当传入userId后被替换

3.Database

​ 用于定义数据库的整体结构,包含所有的实体和DAO,同时提供一个用于创建和管理数据库的入口。拥有一个RoomDatabase的抽象基类,ROOM的数据库类就继承自它,在通过注解标记后,在编译的时候生成该类的实现。通过version参数来标记数据库的版本。

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

这是一个Database类的示例,public abstract UserDao userDao();定义了与数据库交互的 DAO 接口。

注解中entities={User,class}表示该数据库包含一个User实体,也就是文章上面实体示例中的User类,version=1指定当前数据库版本为1,exportSchema = false表示禁用将数据库的架构导出为一个JSON文件,默认情况下,exportSchematrue,表示将生成一个 schema 文件,存储在项目的 build 目录下,供数据库迁移使用,当需要更新数据库等情况下会使用到它。

Room.databaseBuilder(context, AppDatabase.class, "database-name")
    .addMigrations(MIGRATION_1_2)
    .build();

这是一个更新数据库架构的方法,同时需要一个更新的重载方法,以下以为表添加一个新列为例。


public static final Migration MIGRATION_1_2 = new Migration(1, 2) {
    @Override
    public void migrate(SupportSQLiteDatabase database) 
    {
        database.execSQL("ALTER TABLE user_table ADD COLUMN phoneNumber TEXT");
    }
};

3.ROOM数据库的使用

  1. 添加依赖

    在build.gradle中添加

    // app/build.gradle
    
    dependencies {
        // Room components
        implementation "androidx.room:room-runtime:2.5.2"
        annotationProcessor "androidx.room:room-compiler:2.5.2"
    
        // For LiveData (optional)
        implementation "androidx.lifecycle:lifecycle-livedata:2.6.1"
    
        // For Java 8 features (optional, if needed)
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }
    }//将2.5.2替换为所需的ROOM版本
    
  2. 定义实体类、DAO接口、Database

    Entity

    DAO

    Database

  3. 创建数据库客户端(单例模式)

    public class DatabaseClient {
    
        private Context context;
        private static DatabaseClient instance;
        
        private AppDatabase appDatabase;
        
        private DatabaseClient(Context context) {
            this.context = context;
        
            // 创建数据库实例
            appDatabase = Room.databaseBuilder(context, AppDatabase.class, "MyRoomDatabase")
                    .fallbackToDestructiveMigration() // 数据库版本升级时清空数据
                    .build();
        }
        
        public static synchronized DatabaseClient getInstance(Context context) {
            if (instance == null) {
                instance = new DatabaseClient(context);
            }
            return instance;
        }
        
        public AppDatabase getAppDatabase() {
            return appDatabase;
        }
    
    }
    

    在这个例子中,DatabaseClient用于创建和和管理数据库实例AppDatabase.

    ​ 1.成员变量

    ​ context:是android的上下文对象,用于创建数据库实例

    ​ instance:用于保存DatabaseClient的唯一一个实例的静态变量,防止多次创建实例

    ​ appDatabase:表示数据库实例,可以通过它访问与数据库交互的DAO方法

    ​ 2.构造方法private DatabaseClient(Context context)

    ​ 这个方法被声明为私有防止外部直接创建DatabaseClient的实例,并且其只能通过getInstance方法来获取实例。

    Room.databaseBuilder(context, AppDatabase.class, "MyRoomDatabase"):

    ROOM.databaseBuilder是创建数据库实例的方式,

    context是应用的上下文,

    AppDatabase.class是数据库的类,

    MyRoomDatabase是数据库的名字,它将决定数据库储存路径。

    fallbackToDestructiveMigration():这是一个较暴力的迁移策略。在数据库版本不匹配时,ROOM会直接清空数据库并直接创建。可以使用Migration来防止丢失数据。

    build():创建并返回AppDatabase的实例。

    ​ 3.public AppDatabase getAppDatabase():通过该公共方法来获取AppDatabase实例

  4. 在Activity中使用ROOM数据库进行操作

    public class MainActivity extends AppCompatActivity {
    	DatabaseClient databaseClient = DatabaseClient.getInstance(context);
    	AppDatabase appDatabase = databaseClient.getAppDatabase();
    	UserDao userDao = appDatabase.userDao();
        userDao.getAllusers();
    }
    

    首先DatabaseClient databaseClient = DatabaseClient.getInstance(context);声明构造客户端,然后通过AppDatabase appDatabase = databaseClient.getAppDatabase();获取数据库实例,最后通过UserDao userDao = appDatabase.userDao();获取DAO方法接口,通过userDao,可以直接使用已经定义好的操作语句例如userDao.getAllusers();

    @Query("SELECT * FROM user_table ORDER BY user_name ASC")
        LiveData<List<User>> getAllUsers();
    

    这可以查询到表中所有行。但是示例中并没有保存方法返回的数据,仅仅作为一个用法的示例。

4.ROOM数据库的常用注解

  1. @Entity:将一个类映射为数据库的表

    常用属性:

    tableName:指定表名

    indices:创建索引

    primaryKeys:定义主键

    foreignKeys:定义外键

  2. @PrimaryKey:标记主键字段

    常用属性:

    autoGenerate:设置是否自动分配主键值

  3. @ColumnInfo:为类中的字段指定数据库的表中的列的信息

    常用属性:

    name:设置列名

    typeAffinity:设置列的数据类型

    defaultValue:设置列的默认值

  4. @Dao:将一个接口或抽象类标记为数据访问对象

  5. @Insert:将方法标记为插入操作

  6. @Update:将方法标记为更新操作

  7. @Delete:将方法标记为删除操作

  8. @Query:将方法标记为自定义的SQL查询语句的操作

  9. @Database:将一个类标记为ROOM数据库类

    常用属性:

    @entities:定义数据库包含的实体类

    @version:设置数据库的版本号

    @exportSchema:设置是否导出数据库架构

  10. @Embedded:嵌套对象,将嵌套的其他类的字段映射为该类的表的列

  11. @Ignore:忽略字段,防止其被映射到表中

  12. @Transaction:将方法标记为事务操作,保证操作原子性,例如在一个事务中需要连续执行多个数据库操作时数据确保同步

  13. @TypeConverters:将自定义数据类型转换为数据库支持的数据类型

    示例:

    public class Converters {
        @TypeConverter
        public static Date fromTimestamp(Long value) {
            return value == null ? null : new Date(value);
        }
    
        @TypeConverter
        public static Long dateToTimestamp(Date date) {
            return date == null ? null : date.getTime();
        }
    }
    
    @Database(entities = {User.class}, version = 1)
    @TypeConverters({Converters.class})
    public abstract class AppDatabase extends RoomDatabase {
        public abstract UserDao userDao();
    }
    

    可用于储存日期等非基本类型

5.ROOM数据库的优势

  1. 相比于SQLite在运行时验证,ROOM数据库在编译阶段就会验证语法的正确性,减少运行时产生的错误提高安全性。
  2. 对于不太复杂的语句,可以通过大大简化代码。
  3. 通过DAO方法直接返回类型安全的对象或集合,无需手动解析游标
  4. ROOM自动支持事务,确保数据一致性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值