Giới thiệu về Room Persistence Library
Bài đăng này đã không được cập nhật trong 6 năm
Room
là một abstract layer cung cấp các cách thức truy cập cơ sở dữ liệu SQLite. Các lợi ích mà Room
đem lại:
- Đơn giản hoá các hoạt động liên quan đến cơ sở dữ liệu.
- Xác thực các câu truy vấn tại thời điểm biên dịch, điều này giúp tránh các lỗi về cơ sở dữ liệu xảy ra khi ứng dụng đang hoạt động.
Để sử dụng Room library, cần thêm vào dependencies
trong file build.gradle (app)
:
implementation 'android.arch.persistence.room:runtime:1.1.1'
annotationProcessor 'android.arch.persistence.room:compiler:1.1.1'
1. Các thành phần chính của Room
Room bao gồm 3 thành phần chính:
- Entity: Class được lưu trữ trong database. Mỗi class được đánh dấu với annotation
@Entiy
tương ứng với một bảng trong cơ sở dữ liệu. Mỗi thực thể tương ứng với một dòng trong bảng. - DAO (Data Access Object): Bao gồm các phương thức để thao tác với cơ sở dữ liệu.
- Database: Bao gồm database holder và đóng vai trò là điểm truy cập đến cơ sở dữ liệu.
2. Entity
Với mỗi một class được đánh dấu @Enity
, một bảng tương ứng được tạo ra trong cơ sở dữ liệu. Mặc định, Room
tạo ra mỗi cột ứng với một trường trong class. Tuy nhiên, nếu không muốn lưu trữ một trường nào đó, bạn có thể đánh dấu bằng annotation @Ignore
.
Ví dụ:
@Entity
public class User {
@PrimaryKey
public int id;
public String firstName;
public String lastName;
@Ignore
Bitmap picture;
}
Primary key
Mỗi entity phải định nghĩa ít nhất một trường làm khoá chính (kể cả trường hợp chỉ có một trường). Trường được chọn làm khoá chính được chú thích bằng annotation @PrimaryKey
như trong ví dụ trên.
Nếu muốn định nghĩa nhiều trường làm khoá chính, có thể sử dụng thuộc tính primaryKeys
của annotation @Entity
. Ví dụ:
@Entity(primaryKeys = {"firstName", "lastName"})
public class User {
public String firstName;
public String lastName;
@Ignore
Bitmap picture;
}
Custom tên bảng, tên trường
Mặc định, Room
sử dụng tên class để đặt tên cho các bảng. Để đặt tên khác cho bảng, sử dụng thuộc tính tableName
của @Entity
. Tương tự, Room
cũng sử dụng tên các trường trong class để đặt tên các cột trong bảng. Để thay đổi tên mặc định cho các cột, sử dụng annotation @ColumnInfo
với thuộc tính name
. Ví dụ:
@Entity(tableName = "users")
public class User {
@PrimaryKey
public int id;
@ColumnInfo(name = "first_name")
public String firstName;
@ColumnInfo(name = "last_name")
public String lastName;
@Ignore
Bitmap picture;
}
Indices và Uniqueness
Trường hợp muốn đánh chỉ mục để tăng tốc độ truy vấn có thể sử dụng thuộc tính indices
trong annotation @Enitity
. Ví dụ:
@Entity(indices = {@Index("name"),
@Index(value = {"last_name", "address"})})
public class User {
@PrimaryKey
public int id;
public String firstName;
public String address;
@ColumnInfo(name = "last_name")
public String lastName;
@Ignore
Bitmap picture;
}
Trường hợp muốn một trường là duy nhất trong database, có thể gán thuộc tính unique
là true
.
@Entity(indices = {@Index(value = {"first_name", "last_name"},
unique = true)})
public class User {
@PrimaryKey
public int id;
@ColumnInfo(name = "first_name")
public String firstName;
@ColumnInfo(name = "last_name")
public String lastName;
@Ignore
Bitmap picture;
}
Quan hệ giữa các đối tượng
Room
cho phép định nghĩa quan hệ giữa các đối tượng thông qua khoá ngoài. Ví dụ, có một entity khác là Book
, bạn có thể định nghĩa quan hệ với enity User
thông qua annotation @ForeignKey
.
@Entity(foreignKeys = @ForeignKey(entity = User.class,
parentColumns = "id",
childColumns = "user_id"))
public class Book {
@PrimaryKey
public int bookId;
public String title;
@ColumnInfo(name = "user_id")
public int userId;
}
Nested object
Xét ví dụ class Address
bao gồm các trường street
, city
, state
và postCode
, class User
có một trường có kiểu Address
. Tuy nhiên, bạn lại không có nhu cầu lưu Address
thành một bảng riêng, mà muốn bảng User
chứa các thuộc tính của Address
. Trong trường hợp này có thể sử dụng annotation Embedded
.
public class Address {
public String street;
public String state;
public String city;
@ColumnInfo(name = "post_code")
public int postCode;
}
@Entity
public class User {
@PrimaryKey
public int id;
public String firstName;
@Embedded
public Address address;
}
Khi đó, bảng biểu diễn class User
bao gồm các trường id
, firstName
, street
, state
, city
, post_code
.
3. DAO (Data Access Object)
DAO là thành phần chịu trách nhiệm định nghĩa các phương thức truy cập cơ sở dữ liệu.
DAO có thể là một interface hoặc abtract class. Tại thời điểm biên dịch, Room
tạo ra một implementation của class này.
Các thao tác cơ bản với database
Room
cho phép định nghĩa các thao tác thêm, sửa, xoá dữ liệu thông qua các annotation @Insert
, @Update
, @Delete
. Ta có ví dụ sau:
@Dao
public interface MyDao {
@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
public void updateUsers(User... users);
@Delete
public void deleteUsers(User... users);
}
Định nghĩa câu truy vấn
@Query
là annotation chính được sử dụng với DAO, nó cho phép thực hiện đọc, ghi trên cơ sở dữ liệu. Mỗi phương thức được đánh dấu @Query
sẽ được kiểm tra ở thời điểm biên dịch. Điều này nghĩa là, nếu câu truy vấn bị lỗi, sẽ có lỗi compile thay vì lỗi runtime.
Ví dụ một câu truy vấn đơn giản:
@Dao
public interface MyDao {
@Query("SELECT * FROM user")
public User[] loadAllUsers();
}
Ngoài ra, có thể truyền tham số vào trong câu truy vấn.
@Dao
public interface MyDao {
@Query("SELECT * FROM user WHERE age > :minAge")
public User[] loadAllUsersOlderThan(int minAge);
@Query("SELECT * FROM user WHERE age BETWEEN :minAge AND :maxAge")
public User[] loadAllUsersBetweenAges(int minAge, int maxAge);
@Query("SELECT * FROM user WHERE first_name LIKE :search "
+ "OR last_name LIKE :search")
public List<User> findUserWithName(String search);
}
4. Database
Database class được đánh dấu bằng annotation @Database
và phải thoả mãn các điều kiện:
- Phải là abstract class kế thừa class
RoomDatabase
. - Bao gồm danh sách các entity liên kết với cơ sở dữ liệu.
- Bao gồm một abstract method không có tham số truyền vào và trả về một class được đánh dấu với annotation
@Dao
.
Ví dụ:
@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
Tại runtime, bạn có thể gọi một instance của Database
bằng cách gọi phương thức Room.databaseBuilder()
hoặc Room.inMemoryDatabaseBuilder()
.
AppDatabase db = Room.databaseBuilder(getApplicationContext(),
AppDatabase.class, "database-name").build();
Demo
Trên đây là những tìm hiểu cơ bản của mình về Room Library. Các bạn có thể xem ứng dụng demo của mình tại đây.
Tài liệu tham khảo
All rights reserved