一.簡介:
Room 在SQLite上提供了一個抽象層,以便在充分利用SQLite的強大功能的同時,可以流暢地訪問數據庫。
Room包含3個主要組件:
數據庫:包含數據庫持有者,並做爲應用已保留持久性關係型數據的底層鏈接的主要接入點。
@Database註釋
1.是擴展RoomDatabase的抽象類。
2.在註釋中添加與數據庫關聯的實體表。
3.包含具備0個參數且返回使用@Dao 註釋的類的抽象方法。
在運行時,您能夠經過調用Room.databaseBuilder()或Room.inMemoryDatabaseBuilder()獲取Database的實例。
@Entity:表示數據庫中的表
@Dao:包含用於訪問數據庫的方法
二:依賴Room數據庫
1.在App模塊下bulid.Gradle 添加項目的依賴android
//添加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.主鍵:每個實體必須定義至少一個字段做爲主鍵。segmentfault
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爲trueide
@Entity(indices = {@Index(value = "name",unique = true)}) public class User { private String name; }
5.定義對象之間的關係
因爲SQLite是關係型數據庫,你能夠指定對象以前的關係,Room是明確禁止直接使用關係,但Room仍然容許你在實體之間定義外鍵。
例如:若是有另外一個實體叫作Book,你能夠在User實體下使用@ForeignKey註解定義他們之間的關係。post
@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字段ui
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註解this
@Ignore//指示Room須要忽略的字段 private int age;
四:建立一個Dao接口
Dao包含用於訪問數據庫的方法,建立一個操做實體類用@Dao進行註解
@Insert插入語句註釋
@Delete刪除語句註釋
@Update()更新語句註釋
@Query("SELECT * FROM user WHERE first_name=:name")查詢語句spa
@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的抽象類 }
注意:
一、編譯時會檢查SQL語句是否正確
二、不要在主線程中進行數據庫操做
三、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();
END:不負青春,不負韶華;不負夢想,不負將來。