Files
mkdocs/docs/android面试/数据存储/Room数据库.md
2026-01-15 11:53:37 +08:00

7.3 KiB
Raw Blame History

Room数据库

目录


Room架构

Room 组件

┌─────────────┐
│  Entity     │  ←─── 数据模型
└──────┬──────┘
       │
┌──────▼──────┐
│    DAO      │  ←─── 数据访问接口
└──────┬──────┘
       │
┌──────▼──────┐
│  Database   │  ←─── 数据库配置
└─────────────┘

Room 优势

  1. 编译时检查SQL 语句编译时检查
  2. 类型安全:类型安全的数据访问
  3. 支持 LiveData:自动更新 UI
  4. 支持 RxJava:响应式编程
  5. 简化代码:减少样板代码

Entity定义

Entity 注解

// Entity数据模型
@Entity(tableName = "user")
public class User {
    @PrimaryKey(autoGenerate = true)
    private int id;
    
    @ColumnInfo(name = "user_name")
    private String name;
    
    private String email;
    
    private int age;
    
    // Getters and Setters
    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 String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
}

Entity 注解选项

@Entity(
    tableName = "user",
    indices = {@Index("name"), @Index(value = {"name", "age"})},
    foreignKeys = {
        @ForeignKey(
            entity = Department.class,
            parentColumns = "id",
            childColumns = "department_id"
        )
    }
)
public class User {
    @PrimaryKey
    private int id;
    
    @ColumnInfo(name = "department_id")
    private int departmentId;
}

DAO接口

DAO 定义

// DAO数据访问对象
@Dao
public interface UserDao {
    // 查询
    @Query("SELECT * FROM user")
    List<User> getAllUsers();
    
    @Query("SELECT * FROM user WHERE id = :id")
    User getUserById(int id);
    
    @Query("SELECT * FROM user WHERE age > :age")
    List<User> getUsersByAge(int age);
    
    // 插入
    @Insert
    void insertUser(User user);
    
    @Insert
    void insertUsers(User... users);
    
    // 更新
    @Update
    void updateUser(User user);
    
    // 删除
    @Delete
    void deleteUser(User user);
    
    @Query("DELETE FROM user WHERE id = :id")
    void deleteUserById(int id);
}

复杂查询

@Dao
public interface UserDao {
    // 多表查询
    @Query("SELECT * FROM user u INNER JOIN department d ON u.department_id = d.id")
    List<UserWithDepartment> getUsersWithDepartment();
    
    // 参数查询
    @Query("SELECT * FROM user WHERE name LIKE :name AND age > :age")
    List<User> searchUsers(String name, int age);
    
    // 返回 LiveData
    @Query("SELECT * FROM user")
    LiveData<List<User>> getAllUsersLive();
    
    // 返回 FlowableRxJava
    @Query("SELECT * FROM user")
    Flowable<List<User>> getAllUsersFlowable();
}

Database配置

Database 定义

// Database数据库配置
@Database(
    entities = {User.class, Department.class},
    version = 1,
    exportSchema = false
)
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDao userDao();
    public abstract DepartmentDao departmentDao();
    
    private static AppDatabase instance;
    
    public static synchronized AppDatabase getInstance(Context context) {
        if (instance == null) {
            instance = Room.databaseBuilder(
                context.getApplicationContext(),
                AppDatabase.class,
                "app_database"
            ).build();
        }
        return instance;
    }
}

Database 配置选项

Room.databaseBuilder(context, AppDatabase.class, "database_name")
    .allowMainThreadQueries() // 允许主线程查询(不推荐)
    .fallbackToDestructiveMigration() // 破坏性迁移
    .addMigrations(MIGRATION_1_2, MIGRATION_2_3) // 迁移
    .build();

Room迁移

数据库迁移

// 版本1 → 版本2
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        database.execSQL("ALTER TABLE user ADD COLUMN phone TEXT");
    }
};

// 版本2 → 版本3
static final Migration MIGRATION_2_3 = new Migration(2, 3) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        database.execSQL("CREATE TABLE address (" +
            "id INTEGER PRIMARY KEY AUTOINCREMENT," +
            "user_id INTEGER," +
            "address TEXT" +
            ")");
    }
};

// 配置迁移
Room.databaseBuilder(context, AppDatabase.class, "database_name")
    .addMigrations(MIGRATION_1_2, MIGRATION_2_3)
    .build();

Room与LiveData

LiveData 集成

// DAO 返回 LiveData
@Dao
public interface UserDao {
    @Query("SELECT * FROM user")
    LiveData<List<User>> getAllUsers();
    
    @Query("SELECT * FROM user WHERE id = :id")
    LiveData<User> getUserById(int id);
}

// 观察数据变化
userDao.getAllUsers().observe(this, users -> {
    adapter.updateUsers(users);
});

RxJava 集成

// 添加依赖
dependencies {
    implementation 'androidx.room:room-rxjava2:2.3.0'
}

// DAO 返回 Flowable
@Dao
public interface UserDao {
    @Query("SELECT * FROM user")
    Flowable<List<User>> getAllUsers();
}

// 使用
userDao.getAllUsers()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(users -> {
        adapter.updateUsers(users);
    });

Room最佳实践

1. 使用单例模式

// 数据库使用单例
public static synchronized AppDatabase getInstance(Context context) {
    if (instance == null) {
        instance = Room.databaseBuilder(...).build();
    }
    return instance;
}

2. 在后台线程操作

// ✅ 正确:在后台线程操作
new Thread(() -> {
    userDao.insertUser(user);
}).start();

// ❌ 错误:在主线程操作(除非使用 allowMainThreadQueries
userDao.insertUser(user);

3. 使用事务

@Dao
public interface UserDao {
    @Transaction
    @Query("SELECT * FROM user")
    List<User> getAllUsers();
}

面试常见问题

Q1: Room 的优势?

答案:

  1. 编译时检查 SQL
  2. 类型安全
  3. 支持 LiveData
  4. 支持 RxJava
  5. 简化代码

Q2: Room 的组件?

答案:

  1. Entity:数据模型
  2. DAO:数据访问接口
  3. Database:数据库配置

Q3: Room 迁移?

答案:

  • 使用 Migration 类处理数据库升级
  • 定义迁移规则
  • 在 Database 配置中添加迁移

Q4: Room 和 SQLite 的区别?

答案:

  • RoomSQLite 的封装,提供类型安全、编译时检查
  • SQLite:底层数据库,需要手动编写 SQL

最后更新2024年