359 lines
7.3 KiB
Markdown
359 lines
7.3 KiB
Markdown
# Room数据库
|
||
|
||
## 目录
|
||
- [Room架构](#room架构)
|
||
- [Entity定义](#entity定义)
|
||
- [DAO接口](#dao接口)
|
||
- [Database配置](#database配置)
|
||
- [Room迁移](#room迁移)
|
||
- [Room与LiveData](#room与livedata)
|
||
- [Room最佳实践](#room最佳实践)
|
||
- [面试常见问题](#面试常见问题)
|
||
|
||
---
|
||
|
||
## Room架构
|
||
|
||
### Room 组件
|
||
|
||
```
|
||
┌─────────────┐
|
||
│ Entity │ ←─── 数据模型
|
||
└──────┬──────┘
|
||
│
|
||
┌──────▼──────┐
|
||
│ DAO │ ←─── 数据访问接口
|
||
└──────┬──────┘
|
||
│
|
||
┌──────▼──────┐
|
||
│ Database │ ←─── 数据库配置
|
||
└─────────────┘
|
||
```
|
||
|
||
### Room 优势
|
||
|
||
1. **编译时检查**:SQL 语句编译时检查
|
||
2. **类型安全**:类型安全的数据访问
|
||
3. **支持 LiveData**:自动更新 UI
|
||
4. **支持 RxJava**:响应式编程
|
||
5. **简化代码**:减少样板代码
|
||
|
||
---
|
||
|
||
## Entity定义
|
||
|
||
### Entity 注解
|
||
|
||
```java
|
||
// 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 注解选项
|
||
|
||
```java
|
||
@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 定义
|
||
|
||
```java
|
||
// 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);
|
||
}
|
||
```
|
||
|
||
### 复杂查询
|
||
|
||
```java
|
||
@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();
|
||
|
||
// 返回 Flowable(RxJava)
|
||
@Query("SELECT * FROM user")
|
||
Flowable<List<User>> getAllUsersFlowable();
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Database配置
|
||
|
||
### Database 定义
|
||
|
||
```java
|
||
// 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 配置选项
|
||
|
||
```java
|
||
Room.databaseBuilder(context, AppDatabase.class, "database_name")
|
||
.allowMainThreadQueries() // 允许主线程查询(不推荐)
|
||
.fallbackToDestructiveMigration() // 破坏性迁移
|
||
.addMigrations(MIGRATION_1_2, MIGRATION_2_3) // 迁移
|
||
.build();
|
||
```
|
||
|
||
---
|
||
|
||
## Room迁移
|
||
|
||
### 数据库迁移
|
||
|
||
```java
|
||
// 版本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 集成
|
||
|
||
```java
|
||
// 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 集成
|
||
|
||
```java
|
||
// 添加依赖
|
||
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. 使用单例模式
|
||
|
||
```java
|
||
// 数据库使用单例
|
||
public static synchronized AppDatabase getInstance(Context context) {
|
||
if (instance == null) {
|
||
instance = Room.databaseBuilder(...).build();
|
||
}
|
||
return instance;
|
||
}
|
||
```
|
||
|
||
### 2. 在后台线程操作
|
||
|
||
```java
|
||
// ✅ 正确:在后台线程操作
|
||
new Thread(() -> {
|
||
userDao.insertUser(user);
|
||
}).start();
|
||
|
||
// ❌ 错误:在主线程操作(除非使用 allowMainThreadQueries)
|
||
userDao.insertUser(user);
|
||
```
|
||
|
||
### 3. 使用事务
|
||
|
||
```java
|
||
@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 的区别?
|
||
|
||
**答案:**
|
||
- **Room**:SQLite 的封装,提供类型安全、编译时检查
|
||
- **SQLite**:底层数据库,需要手动编写 SQL
|
||
|
||
---
|
||
|
||
*最后更新:2024年*
|