总结:个人见解,使用了一段时间,对于本地频繁操作数据库切数据结构复杂的应用来说,Room并不是很灵活,且需要有一定的SQL编写能力。
一、简介
Room是安卓中SQLite上的一个抽象层应用框架,可以更轻松、更好地保存数据。
我们目前较多使用的是Greendao(GreenDao3.0数据库的简单使用),我们对比执行SQL的效率以及对数据库的访问,可以考虑使用Room了。
Room的不同组件之间的这种关系如图:
取自developer.android.google.cn
注解:
Entity
@Entity
:注解标识创建表,使用@Entity(tableName = "users")
自定义表名
@ColumnInfo
:注解标识数据库列,使用@ColumnInfo(name = "last_name")
自定义列名
@Ignore
:注解表示忽略此对象,数据库中不会创建此列;若使用继承,忽略父类的一个对象,使用@Entity(ignoredColumns = "picture")
@NonNull:
非空
@PrimaryKey
:注解表示为主键,使用@Entity(primaryKeys = {"firstName", "lastName"})
表示复合主键,使用@PrimaryKey(autoGenerate = true)
设置主键自且类型为INTEGER
indices
: 对特定的field
建立索引加速数据库访问,索引:@Entity(indices = @Index("name"))
,复合索引:@Entity(indices = @Index(value = {"last_name", "address"}))
@ForeignKey
用于设置外键@Entity(foreignKeys = @ForeignKey(entity = User.class, parentColumns = "id",childColumns = "user_id"))
@Dao
@Dao:
注解是一个数据访问对象
@Insert:
注解插入
//onConflict = OnConflictStrategy.REPLACE 存在会替换
@Insert(onConflict = OnConflictStrategy.REPLACE)
public void insertUsers(User... users);
@Insert
public void insertBothUsers(User user1, User user2);
@Insert
public void insertUsersAndFriends(User user, List<User> friends);
@Update
注解更新
//返回类型为int的情况,表示更新对象的个数
@Update
public void updateUsers(User... users);
@Delete:
注解为删除
注意:使用条件删除,不能通过@Delete
去做,可以使用@Query('sql')
去执行。
//返回类型为int的情况,表示删除对象的个数
@Delete
public void deleteUsers(User... users);
@Query:
注解为查询
@Query("SELECT * FROM user")
public User[] loadAllUsers();
@Query("SELECT * FROM user WHERE age > :minAge")
public User[] loadAllUsersOlderThan(int minAge);
@Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)")
public List<NameTuple> loadUsersFromRegions(List<String> regions);
//多表查询
@Query("SELECT * FROM book " +
"INNER JOIN loan ON loan.book_id = book.id " +
"INNER JOIN user ON user.id = loan.user_id " +
"WHERE user.name LIKE :userName")
public List<Book> findBooksBorrowedByNameSync(String userName);
二、实战
这部分针对数据的增删改查,以及数据库升级、迁移、与Rxjava的结合使用做介绍
2.1、基本使用
添加依赖
implementation 'androidx.room:room-runtime:2.1.0'
annotationProcessor 'androidx.room:room-compiler:2.1.0'
(1)创建表实体
public class User {
@PrimaryKey(autoGenerate = true)
public int uid;
@ColumnInfo(name = "first_name")
public String firstName;
@ColumnInfo(name = "last_name")
public String lastName;
}
(2)创建Dao(SQ语法我们还是要学习的)
@Dao
public interface UserDao {
@Query("SELECT * FROM user")
List<User> getAll();
@Query("SELECT * FROM user WHERE uid IN (:userIds)")
List<User> loadAllByIds(int[] userIds);
@Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
"last_name LIKE :last LIMIT 1")
User findByName(String first, String last);
@Insert
void insertAll(User... users);
@Delete
void delete(User user);
}
(3)AppDatabase 使用单例,减少开销
@Database(entities = {User.class}, version = 1,exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
//volatile防止重排序
private static volatile AppDatabase mAppDatabase;
public abstract UserDao userDao();
public static AppDatabase getSingleton(Context context) {
if (mAppDatabase == null) {
synchronized (AppDatabase.class) {
if (mAppDatabase == null) {
//主线程使用.allowMainThreadQueries().build();创建
mAppDatabase = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "user.db")
.allowMainThreadQueries()
.build();
}
}
}
return mAppDatabase;
}
}
(4)使用
AppDatabase appDatabase = AppDatabase.getSingleton(this);
User user = new User(0,"张","三");
User user1 = new User(1,"李","四");
appDatabase.userDao().insertAll(user);
appDatabase.userDao().insertAll(user1);
List<User> userList = appDatabase.userDao().getAll();
2.2 类型转换器
定义类型转换器
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();
}
}
使用类型转换器
(1) 放在Database,那么该数据库中的所有Daos和Entities都可以使用它。
(2) 放在Dao,Dao中的所有方法都可以使用它。
(3) 放在Entity,实体的所有字段都可以使用它。
(4) 放在Entity字段上,则只有该字段才能使用它。
(5) 放在Dao方法上,该方法的所有参数都可以使用它。
//放在Dao方法参数上,那么只有该字段才能使用它。
@TypeConverters({Converters.class})
2.3 与RxJava并肩作战
添加依赖
implementation 'androidx.room:room-rxjava2:2.1.0-beta01'
@Query
方法:房间支持类型的返回值 Publishe
r, Flowable
和 Observable`。
@Insert
,@Update
及@Delete
方法:2.1.0室和更高版本支持返回类型的值 Completable
,Single<T>
和 Maybe<T>
。
@Dao
public interface MyDao {
@Query("SELECT * from user where id = :id LIMIT 1")
public Flowable<User> loadUserById(int id);
// Emits the number of users added to the database.
@Insert
public Maybe<Integer> insertLargeNumberOfUsers(List<User> users);
// Makes sure that the operation finishes successfully.
@Insert
public Completable insertLargeNumberOfUsers(User... users);
/* Emits the number of users removed from the database. Always emits at
least one user. */
@Delete
public Single<Integer> deleteUsers(List<User> users);
}
2.4 数据库升级
要使迁移逻辑按预期运行,使用完整查询,而不是引用表示查询的常量,否则会造成数据丢失
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("CREATE TABLE `Fruit` (`id` INTEGER, "
+ "`name` TEXT, PRIMARY KEY(`id`))");
}
};
static final Migration MIGRATION_2_3 = new Migration(2, 3) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE Book "
+ " ADD COLUMN pub_year INTEGER");
}
};
Room.databaseBuilder(getApplicationContext(), MyDb.class, "database-name")
.addMigrations(MIGRATION_1_2, MIGRATION_2_3).build();
网友评论