ndroid 數據庫Room的開發使用詳解
一.簡介:
Room 在SQLite上提供了一個抽象層,以便在充分利用SQLite的強大功能的同時,能夠流暢地訪問數據庫。
Room包含3個主要組件:
數據庫:包含數據庫持有者,并作為應用已保留持久性關系型數據的底層連接的主要接入點。
@Database注釋
1.是擴展RoomDatabase的抽象類。
2.在注釋中添加與數據庫關聯的實體表。
3.包含具有0個參數且返回使用@Dao 注釋的類的抽象方法。
在運行時,您可以通過調用Room.databaseBuilder()或Room.inMemoryDatabaseBuilder()獲取Database的實例。
@Entity:表示數據庫中的表
@Dao:包含用于訪問數據庫的方法


二:依賴Room數據庫
1.在App模塊下bulid.Gradle 添加項目的依賴
//添加Room依賴
implementation 'androidx.room:room-runtime:2.2.5'
annotationProcessor 'androidx.room:room-compiler:2.2.5'


三:創建一個實體類Entity
@Entity
public class User {
@PrimaryKey(autoGenerate = true)//主鍵是否自動增長,默認為false
private int id;
private String name;
private int 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;
}
}


1.主鍵:每一個實體必須定義至少一個字段作為主鍵。
1.可以在實體中@PrimaryKey(autoGenerate = true)注解,同時你也可以使用autoGenerate屬性,可以通過Room來自動分配ID
2.也可以通過@Entity@Entity(primaryKeys = {"id","name"})如果有組合主鍵
2.通常Room會使用類名作為數據庫的表名,如果你希望自定義表名在@Entity(tableName = “my_user”),注意: SQLite中,表名是不區分大小寫的
3.Room用變量名稱作為數據庫表的字段名稱,如果你希望字段名稱和變量名稱不一樣,在變量出添加
public class User {
@ColumnInfo(name = "first_name")
private String name;
}
4.索引和唯一性
根據你操作數據的方式你可能需要通過索引來提高查詢數據庫的速度,通過@Entity添加indices屬性,有些字段設置唯一性,可以通過@Index注解下設置unique為true
@Entity(indices = {@Index(value = "name",unique = true)})
public class User {
private String name;
}
5.定義對象之間的關系
由于SQLite是關系型數據庫,你可以指定對象之前的關系,Room是明確禁止直接使用關系,但Room仍然允許你在實體之間定義外鍵。
例如:如果有另一個實體叫做Book,你可以在User實體下使用@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;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public int getBookId() {
return bookId;
}
public void setBookId(int bookId) {
this.bookId = bookId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
6.創建嵌套對象
你可以使用@Embedded批注來表示要分解到表中子字段的對象
例如:我們的User類可以包含Address類型的字段,它表示名為street,city,state和postCode的字段的組合。要將組合列分別存儲在表中,請在User類中包含使用@Embedded注釋的Address字段
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;
}
故這個表示User對象的表包含具有以下名稱的列:id,firstName,street,state,city和post_code。
@Embedded(prefix = “address_”)如果實體具有多個相同類型的嵌入字段,則可以通過設置prefix屬性使得每一個列保持唯一,把address_嵌入到列名的開頭
7.忽略成員變量
如果你不想保留某些成員變量,可以使用@Ignore注解
@Ignore//指示Room需要忽略的字段
private int age;
四:創建一個Dao接口
Dao包含用于訪問數據庫的方法,創建一個操作實體類用@Dao進行注解
@Insert插入語句注釋
@Delete刪除語句注釋
@Update()更新語句注釋
@Query(“SELECT * FROM user WHERE first_name=:name”)查詢語句
@Dao
public interface UserDao {
/*插入數據User*/
@Insert
void insert(User user);
@Query("SELECT * FROM user")//從user表中查詢所有,user是User實體類默認在Room中創建的表,也可以通過@Entity(tableName = "my_user"),指定表名,故這個表名就變成my_user
List<User> getAllUsers();
@Query("SELECT * FROM user WHERE first_name=:name")//設置篩選條件name,來查詢這個first_name是表名first_name字段,通過@ColumnInfo(name = "first_name")來設置表字段名
List<User> getUsersByName(String name);
}
五:創建一個數據庫持有者類
@Database(entities = {User.class},version = 6,exportSchema = false)
public abstract class UserDatabase extends RoomDatabase {
private static final String DB_NAME="UserDatabase.db";
private static volatile UserDatabase instance;//創建單例
public static synchronized UserDatabase getInstance(Context context){
if (instance==null){
instance=create(context);
}
return instance;
}
/**
* 創建數據庫*/
private static UserDatabase create(Context context) {
return Room.databaseBuilder(context,UserDatabase.class,DB_NAME)
.allowMainThreadQueries()//允許在主線程操作數據庫,一般不推薦;設置這個后主線程調用增刪改查不會報錯,否則會報錯
.fallbackToDestructiveMigration()//該方法能在升級異常重新創建數據庫,但所有的數據都會丟失
.addMigrations(new Migration(1,4) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("alter table user add price TEXT");//添加一個字段 price升級數據庫版本到4
}
})
.build();
}
public abstract UserDao getUserDao();//這個是必要的,創建DAO的抽象類
}
注意:
1、編譯時會檢查SQL語句是否正確
2、不要在主線程中進行數據庫操作
3、RoomDatabase最好使用單例模式
如果不設置數據庫在主線程操作的話就會報錯,錯誤提示為


故需要使用數據庫最好在new Thread().start()子線程中使用,或者Handler 或者AsyncTask或者RXJava異步實現。
Room數據庫升級
//第一步修改版本號為2,要升級的版本
@Database(entities = {User.class},version = 2,exportSchema = false)
//第二步,添加addMigrations()添加數據庫升級
Room.databaseBuilder(context,UserDatabase.class,DB_NAME)
.addMigrations(new Migration(1,2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("alter table user add go TEXT");//在user 表中添加一個字段go 類型為TEXT
Log.d("aa",database.getVersion()+"");
}
})
.build();
//第三步在Entity實體類User中添加屬性
private String go;
public String getGo() {
return go;
}
public void setGo(String go) {
this.go = go;
}
//這樣數據庫版本就升級到了2,就可以使用了
六:Room數據庫使用
通過開辟子線程插入一條數據,也可以結合RXJava和Handler和AsyncTask等異步實現
User user=new User();
user.setAge(2223);
user.setName("eees");
user.setGo("wogo");
new Thread(new Runnable() {
@Override
public void run() {
UserDatabase.getInstance(NineActivity.this).getUserDao().insert(user);
Log.d("TAG","插入一條數據");
}
}).start();
版權聲明:本文內容由互聯網用戶自發貢獻,該文觀點僅代表作者本人。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如發現本站有涉嫌抄襲侵權/違法違規的內容, 請發送郵件至 舉報,一經查實,本站將立刻刪除。