目錄html
簡介java
導入工程android
使用流程概況sql
一個簡單的小Demo數據庫
自定義表名 tableName 自定義字段名@ColumnInfoapp
索引 @Indexide
簡介
Android 2017 IO大會推出了官方數據庫框架:Room。Room其實就只是對原生的SQLite API進行了一層封裝。不得不說google其實早應該出SQLite的ORM了,由於Android的SQLite誰用誰知道,沒有任何封裝的字符輸入。若是不對着Demo基本上會有記不起來的一兩個關鍵字的時候,並且徹底手敲容易輸入錯誤。固然還有不少其餘的Android ORM框架例如OrmLite、GreenDao 和 Sugar。可是本着Google爸爸的東西確定有牛逼的地方,咱們仍是須要學習一下怎麼使用。
這裏解釋一下什麼是ORM,對象關係映射(Object Relational Mapping,簡稱ORM)模式是一種爲了解決面向對象與關係數據庫存在的互不匹配的現象的技術。其實更好的說明就是,對數據庫指令的二次封裝。使其使用更加簡單、輕鬆、緩解記不住指令的尷尬。
參考文檔:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2017/0525/7971.html
數據庫升級遷移:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2017/0728/8278.html
導入工程
這裏只說明Android studio的導入
1.首先在build.gradle裏添加
allprojects { repositories { jcenter() google() } }
2.而後在添加依賴
implementation 'android.arch.persistence.room:runtime:1.0.0' annotationProcessor "android.arch.persistence.room:compiler:1.0.0"
使用流程概況
由於建立步驟較多因此這裏簡單先給一個流程,給你們有一個簡單的概念:
- 建立數據class,使用的註釋是:@Entity
- 建立Dao 數據操做抽象class,使用的註釋是:@Dao(負責提供操做數據的方法,好比基本的增長、更新、查找、刪除。固然除了這些基本的,更復雜的咱們將在後續深刻學習)
- 建立應用程序數據庫的抽象class,使用的註釋是:@Database(負責建立應用數據庫,組合「數據class」與「數據操做class」,還有數據庫版本)
- 實例化使用數據庫
一個簡單的小Demo
在深刻學習前,咱們先來一個簡單的小demo演示一下建立流程與使用。
1.首先是建立數據class,它使用關鍵註釋是@Entity,這個class表明着一列的數據表(裏面包含着主鍵id(這是是必需的)、內容1標題、內容2標題等等)
import androidx.room.ColumnInfo; import androidx.room.Entity; import androidx.room.PrimaryKey; @Entity //重點!這個是關鍵.數據class必需使用@Entity註釋 public class MyData { @PrimaryKey //@PrimaryKey = 主鍵 @ColumnInfo(name = "id") public int id; @ColumnInfo(name = "name")//這個表明了這個數據標題名稱 public String name; public String content; //固然不寫 @ColumnInfo(name = "content") 也是能夠的,由於數據名稱能夠默認爲變量名稱。 }
2.建立Dao 數據操做抽象class,它使用關鍵註釋是@Dao,這個class負責提供操做數據的方法(好比基本的增長、更新、查找、刪除)
import java.util.List; import androidx.room.Dao; import androidx.room.Delete; import androidx.room.Insert; import androidx.room.OnConflictStrategy; import androidx.room.Query; import androidx.room.Update; @Dao //重點! 這個是關鍵,數據操做的class必需使用@Dao來註釋 public abstract class MyDao { //另外注意它是一個抽象類 @Insert(onConflict = OnConflictStrategy.REPLACE) //@Insert = 插入, onConflict = 若是衝突 OnConflictStrategy.REPLACE = 若是衝突就替換 public abstract void insert(MyData... data); //添加了插入註釋後,這個方法就能夠當作插入數據的方法使用 @Update public abstract void update(MyData... data);// @Update = 更新 @Delete public abstract void delete(MyData... data);// @Delete = 刪除 @Query("select * from MyData") abstract List<MyData> getAll(); //@Query = 查詢 ,這裏的註釋括號裏的內容表明這查詢的關鍵詞,能夠用於篩查想要的數據。 }
3.建立應用程序數據庫的抽象class,使用的註釋是:@Database(負責建立應用數據庫,組合數據class與數據操做class,還有數據庫版本)
/** * 重點!應用數據庫class必需使用Database註釋 * entities 實體 = 咱們的數據class MyData,注意它使用了{}包裹 * version = 1 數據庫版本號 * exportSchema = false 導出模式 */ @Database(entities = {MyData.class},version = 1,exportSchema = false) public abstract class AppDatabase extends RoomDatabase { public abstract MyDao Dao(); private static AppDatabase mAppDataBase; public static AppDatabase getI(Context context){ //實現單例模式 if (mAppDataBase == null){ mAppDataBase = Room.databaseBuilder(context,AppDatabase.class,"data.db")//data.db 是你的數據庫名稱 .build(); } return mAppDataBase; } }
注意!這裏使用的是單例模式。 還有另外,你要記住你的數據庫名稱。另外數據庫是容許在主線程裏建立的,可是不建議在主線程裏建立。若是你非要建立,能夠添加屬性後在UI線程中建立。
mAppDataBase = Room.databaseBuilder(context,AppDatabase.class,"data.db") .allowMainThreadQueries() .build();
4.在activity的子線程裏實例化而且使用數據庫。
public class RoomActivity extends AppCompatActivity { private static final String TAG = "RoomActivity"; private Button mBtnGetData; private AppDatabase appDatabase; private TextView mTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_room); /** * 實例化應用數據庫 */ new Thread(new Runnable() { @Override public void run() { appDatabase = AppDatabase.getI(RoomActivity.this); MyDao dao = appDatabase.Dao();//獲得實例化的數據操做class MyData data = new MyData();//實例一個數據class data.id = 101; data.name = "橘子"; data.content = "酸酸的"; MyData data2 = new MyData(); data2.id = 102; data2.name = "蘋果"; data2.content = "脆脆的"; //由於我在MyDao的insert插入方法裏寫的是數組參數,因此也能夠多個添加 dao.insert(data,data2); Log.e(TAG, "數據導入完成"); } }).start(); mTextView = (TextView)findViewById(R.id.textView); mBtnGetData = (Button)findViewById(R.id.btn_getdata); mBtnGetData.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { new Thread(new Runnable() { @Override public void run() { MyDao dao = appDatabase.Dao(); final StringBuffer sb = new StringBuffer(); sb.append("數據庫內容是:"+"\n"+"-------------------------------\n"); List<MyData> datas = dao.getAll();//獲得全部數據的List for (MyData data : datas){ sb.append("id : "+String.valueOf(data.id)+"\n"); sb.append("name : "+data.name+"\n"); sb.append("content : "+data.content+"\n"); sb.append("-------------------------------\n"); } runOnUiThread(new Runnable() { @Override public void run() { mTextView.setText(sb.toString()); } }); } }).start(); } }); } }
以上是建立數據庫、插入數據、查詢數據在線程中的操做。建立數據庫、插入數據和查詢數據最好都在子線程裏操做,儘可能不要在主線程裏操做數據庫。另外注意!若是你在子線程裏建立了數據庫,那麼你在主線程中就沒法獲取數據,必定要在子線程裏獲取數據。
效果圖:
深刻學習 @Entity使用
@Entity 是用來建立表格與表格中一列的內容的。Room 會爲實體類中定義的每一個字段在數據庫中建立「列」。
下面這個代碼塊展現瞭如何定義一個實體
@Entity public class MyData { @PrimaryKey //@PrimaryKey = 主鍵 @ColumnInfo(name = "id") public int id; @ColumnInfo(name = "name") public String name; public String content; @Ignore //使用@Ignore的數據將不會在數據庫建立此數據的一列 public Bitmap bitmap; }
另外若是你有不須要數據庫建立字段列,你可使用@Ignore 進行註釋。爲了可以保存某個字段,Room必須可以對它進行操做。你可使用public修飾符,或者你能夠提供getter和setter方法。若是你選擇後者,記住Room是基於JavaBeans約定的。
自定義表名 tableName 自定義字段名@ColumnInfo
在一般不添加自定義表名的屬性狀況下,表名是默認class名的,可是若是有需求自定義能夠這樣實現
@Entity (tableName = "Data")//建立自定義表名稱 public class MyData { @PrimaryKey public int id; @ColumnInfo(name = "name") public String name; @ColumnInfo(name = "content") public String content; }
另外你須要注意一點,表名對大小寫是有區分的。
主鍵@PrimaryKey
一份數據實體,一定包含一個主鍵變量(或者叫主鍵字段) 。
自增主鍵 @PrimaryKey (autoGenerate = true)
若是你不想本身添加主鍵值,能夠設定這個屬性,讓主鍵值自增
@Entity public class MyData { @PrimaryKey (autoGenerate = true) public int id; @ColumnInfo(name = "name") public String name; @ColumnInfo(name = "content") public String content; }
咱們試試不添加主鍵內容,讓它自增
MyDao dao = appDatabase.Dao();//獲得實例化的數據操做class MyData data = new MyData();//實例一個數據class data.name = "橘子"; data.content = "酸酸的"; MyData data2 = new MyData(); data2.name = "蘋果"; data2.content = "脆脆的"; dao.insert(data,data2);//由於我在MyDao的insert插入方法裏寫的是數組參數,因此也能夠多個添加
效果圖:
組合主鍵 primaryKeys
@Entity (primaryKeys = {"id","num"}) public class MyData { public int id; public int num; @ColumnInfo(name = "name") public String name; @ColumnInfo(name = "content") public String content; }
索引 @Index
瞭解索引:假如咱們比喻數據庫是一份字典,若是不添加索引咱們去查找某個數據,數據庫是逐行逐列的去查詢直到整個字典被遍歷完成。這樣搜索必然慢一些,而這個時候咱們能夠添加索引,原理跟你在查字典的時候在索引頁面裏去查詢關鍵信息(好比拼音或者筆畫查找)而後在逐步縮小範圍最終找到想要的信息而且鎖定頁數。
使用範圍:索引並非萬能的,也有它的優勢與缺點,索引能夠增長更新、刪除、查詢的速度,可是會增長插入數據的速度。使用索引不適合使用在:1.數據量少的狀況 2.有大量null值,不值得索引查詢 3.頻繁更新、插入的數據庫,插入修改操做頻繁反而更慢。
其餘:索引的建立不須要添加什麼標示字符串,你只須要告訴數據庫須要建立索引的列,它會自動添加數據索引。
廢話了這麼多,咱們開始建立索引:
單列索引:
@Entity (indices = {@Index("name")})//這裏說明了,咱們的name須要索引 public class MyData { @PrimaryKey(autoGenerate = true) public int id; @ColumnInfo(name = "name") public String name; @ColumnInfo(name = "content") public String content; }
多列索引(組合索引):
@Entity (indices = {@Index(value = {"name","content"})})//這個是索引 public class MyData { @PrimaryKey(autoGenerate = true) public int id; @ColumnInfo(name = "name") public String name; @ColumnInfo(name = "content") public String content; }
索引惟一性:
你能夠經過在@Index註解下設置unique爲true,便可強制實現該字段的惟一性。防止name與content內容一致
@Entity (indices = {@Index(value = {"name","content"},unique = true)})
外鍵 @ForeignKey
瞭解外鍵:外鍵是什麼?按照字面解讀「外部的鍵值」?恩,部分解釋到了它的用處。它的確是關聯2個列的關鍵功能。百度這麼解釋的:若是公共關鍵字在一個關係中是主關鍵字,那麼這個公共關鍵字被稱爲另外一個關係的外鍵。因而可知,外鍵表示了兩個關係之間的相關聯繫。以另外一個關係的外鍵做主關鍵字的表被稱爲主表,具備此外鍵的表被稱爲主表的從表。外鍵又稱做外關鍵字。外鍵有2個基本特性:1.約束插入的值 (你沒法插入一個沒有被建立的主鍵)2.被主鍵影響(好比主鍵刪除,主鍵下的所有外鍵會被刪除)
使用範圍:聊天記錄、好友列表等等須要主次分類關聯數據的地方.
其餘:注意!Android 好像是不容許主鍵操做外鍵,好比直接從主鍵獲得外鍵數據。可是它是容許關聯主外鍵的
代碼演示:
爲了思惟連續,我將貼全代碼。
步驟一 建立數據實體class
我將分別建立 書架數據類-Classify 與 書籍數據類-Book。
書架數據類-Classify
@Entity public class Classify { @PrimaryKey (autoGenerate = true) public int id;//書架id public String classifyName;//書架名稱 }
書籍數據類-Book 請注意,我給Book添加的外鍵屬性。
//重點!這裏寫入了外鍵屬性!聲明瞭,書架Classify是個人主鍵 , 父類列 = 書架Classify裏的id 子類列 = 我下面建立的classifyId變量 @Entity (foreignKeys = @ForeignKey(entity = Classify.class,parentColumns = "id",childColumns = "classifyId")) public class Book { @PrimaryKey (autoGenerate = true) public int bookId;//書籍id public String bookName;//書籍名稱 public int classifyId;//書架id }
步驟二 建立數據操做Dao類
也是分別2個ClassifyDao 與 BookDao
@Dao public abstract class ClassifyDao { @Insert(onConflict = OnConflictStrategy.REPLACE) public abstract void insert(Classify... data); @Update public abstract void update(Classify... data); @Delete public abstract void delete(Classify... data); @Query("select * from Classify") public abstract List<Classify> getAll(); }
@Dao public abstract class BookDao { @Insert(onConflict = OnConflictStrategy.REPLACE) public abstract void insert(Book... data); @Update public abstract void update(Book... data); @Delete public abstract void delete(Book... data); @Query("select * from Book") public abstract List<Book> getAll(); }
步驟三 建立應用數據庫
@Database(entities = {Classify.class,Book.class},version = 1,exportSchema = false) public abstract class AppDatabase extends RoomDatabase { public abstract ClassifyDao classifyDao(); public abstract BookDao bookDao(); private static AppDatabase mAppDataBase; public static AppDatabase getI(Context context){ //實現單例模式 if (mAppDataBase == null){ mAppDataBase = Room.databaseBuilder(context,AppDatabase.class,"data.db")//data.db 是你的數據庫名稱 .build(); } return mAppDataBase; } }
老樣子,我導入了2個返回操做抽象類的方法,使用了單例模式獲得應用數據庫實例。
步驟四 建立應用數據庫實例、插入數據、查詢數據
public class RoomActivity extends AppCompatActivity { private static final String TAG = "RoomActivity"; private Button mBtnGetData,mBtnSetData; private AppDatabase appDatabase; private TextView mTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_room); mTextView = (TextView)findViewById(R.id.textView); mBtnGetData = (Button)findViewById(R.id.btn_getdata); mBtnSetData = (Button)findViewById(R.id.btn_setdata); mBtnSetData.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { /** * 實例化應用數據庫 */ new Thread(new Runnable() { @Override public void run() { appDatabase = AppDatabase.getI(RoomActivity.this);//單例模式獲得應用數據庫 ClassifyDao classifyDao = appDatabase.classifyDao();//獲得實例化的數據操做class Classify data = new Classify();//實例一個數據class data.classifyName = "科幻類"; Classify data2 = new Classify(); data2.classifyName = "技術類"; classifyDao.insert(data,data2); BookDao bookDao = appDatabase.bookDao(); Book book1 = new Book(); book1.bookName = "三體"; book1.classifyId = 1;//寫入主鍵id Book book2 = new Book(); book2.bookName = "黑暗森林"; book2.classifyId = 1; Book book3 = new Book(); book3.bookName = "Java從入門到精通"; book3.classifyId = 2; Book book4 = new Book(); book4.bookName = "Android第一行代碼"; book4.classifyId = 2; bookDao.insert(book1,book2,book3,book4); Log.e(TAG, "數據導入完成"); } }).start(); } }); mBtnGetData.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { new Thread(new Runnable() { @Override public void run() { final StringBuffer sb = new StringBuffer(); sb.append("數據庫內容是:"+"\n"+"-------------------------------\n"); ClassifyDao classifyDao = appDatabase.classifyDao(); BookDao bookDao = appDatabase.bookDao(); List<Classify> classifyList = classifyDao.getAll(); List<Book> bookList = bookDao.getAll(); for (Classify classify : classifyList){ sb.append("ClassifyId:"+String.valueOf(classify.id)+"\n"); sb.append("Name:"+classify.classifyName+"\n"); sb.append("-------------------------------\n"); } for (Book book : bookList){ sb.append("BookId:"+String.valueOf(book.bookId)+"\n"); sb.append("Name:"+book.bookName+"\n"); sb.append("ClassifyId:"+book.classifyId+"\n"); sb.append("-------------------------------\n"); } runOnUiThread(new Runnable() { @Override public void run() { mTextView.setText(sb.toString()); } }); } }).start(); } }); } }
惟一須要注意的地方,我寫入的主鍵id,由於我在書架數據class標示的id是自增,而後我又建立了2個書架,因此在書籍class裏寫入的主鍵id是1和2。到此爲止,演示外鍵的demo代碼就已經貼全了。
效果圖:
外鍵的功能探索:
約束:
或許某些同窗會這麼有這些疑問,ヾ(。`Д´。) 看到目前爲止外鍵好像並無什麼用啊。恩,這是我一開始的疑惑,特別是我發現還須要手動添加外鍵(原諒我以前沒有接觸過數據庫),這不是雞肋麼。下面,咱們就來演示外鍵的功能之一」約束「。
Classify data = new Classify();//實例一個數據class data.classifyName = "科幻類"; Classify data2 = new Classify(); data2.classifyName = "技術類"; classifyDao.insert(data,data2); BookDao bookDao = appDatabase.bookDao(); Book book1 = new Book(); book1.bookName = "三體"; book1.classifyId = 1; Book book2 = new Book(); book2.bookName = "黑暗森林"; book2.classifyId = 1; Book book3 = new Book(); book3.bookName = "Java從入門到精通"; book3.classifyId = 3; Book book4 = new Book(); book4.bookName = "Android第一行代碼"; book4.classifyId = 3; bookDao.insert(book1,book2,book3,book4);
由於,咱們只建立了2個書架。按照自增id,最多自增到了「2」。因此咱們這裏給它一個錯誤的書架id 「3」,看看會出現什麼狀況。
恩,報錯了。咱們看看,爲何報錯了?
android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed (code 787) at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method) at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:782) at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788) at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86) at androidx.sqlite.db.framework.FrameworkSQLiteStatement.executeInsert(FrameworkSQLiteStatement.java:51) at androidx.room.EntityInsertionAdapter.insert(EntityInsertionAdapter.java:80) at com.example.user.demo.room.BookDao_Impl.insert(BookDao_Impl.java:79) at com.example.user.demo.room.RoomActivity$1$1.run(RoomActivity.java:56) at java.lang.Thread.run(Thread.java:761)
報錯的緣由是咱們添加了一個不存在的主鍵id,咱們的外鍵功能成功的約束了。
關聯操做:
外鍵還有一個功能,關聯操做,下面咱們來演示一個主鍵id的列被刪除了,它關聯的外鍵也被刪除的功能。在代碼相同的部分我就不貼了,能夠參考上面已經貼出的代碼。下面將貼出具體實現的代碼。
在以前的Book數據class的外鍵屬性裏添加了onDelete屬性:
@Entity (foreignKeys = @ForeignKey(entity = Classify.class, parentColumns = "id", childColumns = "classifyId", onDelete = CASCADE))//重點!咱們添加onDelete屬性爲CASCADE串聯.表示刪除操做串聯 public class Book { @PrimaryKey (autoGenerate = true) public int bookId; public String bookName; public int classifyId; }
下面來實現查找一個數據列的方法:
@Query("select * from Classify where id = :num ") public abstract Classify getClassify(int num);
這裏在ClassifyDao類裏添加了一個根據id查找實體數據列的方法。這裏你只要先稍微瞭解。後續我將詳解解釋查詢功能部分。
在activity裏實現:
首先,導入數據的部分不變依然是上面的操做,咱們在獲取數據的步驟裏添加了以下代碼:
mBtnGetData.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { new Thread(new Runnable() { @Override public void run() { final StringBuffer sb = new StringBuffer(); sb.append("數據庫內容是:"+"\n"+"-------------------------------\n"); ClassifyDao classifyDao = appDatabase.classifyDao(); BookDao bookDao = appDatabase.bookDao(); Classify classify = classifyDao.getClassify(2);//找到id爲2的列 classifyDao.delete(classify);//刪除這個列 List<Classify> classifyList = classifyDao.getAll();//獲得所有書架數據列 List<Book> bookList = bookDao.getAll();//獲得所有書籍數據列 for (Classify classifyItem : classifyList){ sb.append("ClassifyId:"+String.valueOf(classifyItem.id)+"\n"); sb.append("Name:"+classifyItem.classifyName+"\n"); sb.append("-------------------------------\n"); } for (Book bookItem : bookList){ sb.append("BookId:"+String.valueOf(bookItem.bookId)+"\n"); sb.append("Name:"+bookItem.bookName+"\n"); sb.append("ClassifyId:"+bookItem.classifyId+"\n"); sb.append("-------------------------------\n"); } runOnUiThread(new Runnable() { @Override public void run() { mTextView.setText(sb.toString()); } }); } }).start(); } });
先找到id爲2的列,而後在刪除這個列(刪除的方法請向上看以前的代碼),而後在分別讀出數據庫裏的數據。
效果圖:
刪除了主鍵書架裏,id等於2 名稱是技術類的書架,可是它的外鍵數據也被刪除了。關聯刪除實現了。
嵌入對象 @Embedded
有時你可能想把一個entity或者一個POJOs(數據類)做爲一個總體看待。這種狀況下,你可使用@Embedded註解,表示你想把一個對象分解爲表的子字段。而後你就能夠像其它獨立字段那樣查詢這些嵌入的字段。通俗點的說法就是,讓帶有多個成員的類的每一個變量都做爲表中的字段。下面我就來演示一下如何添加一個class做爲字段對象。
首先咱們須要建立實體數據,並添加對象:
@Entity public class Book { @PrimaryKey (autoGenerate = true) public int bookId; public String bookName; @Embedded //重點,這裏使用的是下面的內部class做爲對象 public Detailed detailed; } class Detailed{ public String author; public String press; @ColumnInfo(name = "paginal_number") public int num; }
在activity裏插入數據、查詢數據:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_room); mTextView = (TextView)findViewById(R.id.textView); mBtnGetData = (Button)findViewById(R.id.btn_getdata); mBtnSetData = (Button)findViewById(R.id.btn_setdata); mBtnSetData.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { /** * 實例化應用數據庫 */ new Thread(new Runnable() { @Override public void run() { appDatabase = AppDatabase.getI(RoomActivity.this);//單例模式獲得應用數據庫 BookDao bookDao = appDatabase.bookDao(); Book book1 = new Book(); book1.bookName = "Android第一行代碼"; Detailed detailed = new Detailed(); detailed.author = "郭霖"; detailed.press = "人民郵電出版社"; detailed.num = 570; book1.detailed = detailed; bookDao.insert(book1); Log.e(TAG, "數據導入完成"); } }).start(); } }); mBtnGetData.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { new Thread(new Runnable() { @Override public void run() { final StringBuffer sb = new StringBuffer(); sb.append("數據庫內容是:"+"\n"+"-------------------------------\n"); BookDao bookDao = appDatabase.bookDao(); List<Book> bookList = bookDao.getAll(); for (Book bookItem : bookList){ sb.append("BookId:"+String.valueOf(bookItem.bookId)+"\n"); sb.append("Name:"+bookItem.bookName+"\n"); sb.append("author:"+bookItem.detailed.author+"\n"); sb.append("press"+bookItem.detailed.press+"\n"); sb.append("paginal_number:"+bookItem.detailed.num+"\n"); sb.append("-------------------------------\n"); } runOnUiThread(new Runnable() { @Override public void run() { mTextView.setText(sb.toString()); } }); } }).start(); } }); } }
效果圖:
深刻學習@Dao
在room框架裏@Dao註釋的的class 都是用於數據增、刪、查、更新方法的提供。另外你須要注意它必需使用接口或者抽象class來實現。
建立Dao Class
@Dao 註釋的Class對具體操做那個數據class並無要求,你能夠將全部的操做方法都放如一個@Dao類,也能夠分別添加多個@Dao類。
重載方法操做不一樣表
老樣子,按照個人習慣,不厭其煩的貼全代碼
步驟一 建立操做Dao
@Dao public abstract class AllDao { @Insert(onConflict = OnConflictStrategy.REPLACE) public abstract void insert(Fruits... data); @Insert(onConflict = OnConflictStrategy.REPLACE) public abstract void insert(Drinks...data); @Update public abstract void update(Fruits... data); @Update public abstract void update(Drinks... data); @Delete public abstract void delete(Fruits... data); @Delete public abstract void delete(Drinks... data); @Query("select * from Fruits") public abstract List<Fruits> getFruitsAll(); @Query("select * from Drinks") public abstract List<Drinks> getDrinksAll(); }
咱們這裏重載了分別爲Fruits水果 與 Drinks飲料的 數據庫操做方法
步驟二 建立對應的數據class 水果與飲料
水果
@Entity public class Fruits { @PrimaryKey(autoGenerate = true) public int id; public String name; public Fruits(String name){ this.name = name; } }
飲料
@Entity public class Drinks { @PrimaryKey(autoGenerate = true) public int id; public String name; public Drinks(String name){ this.name = name; } }
步驟三 建立應用程序數據庫的抽象class
@Database(entities = {Drinks.class,Fruits.class},version = 1,exportSchema = false) //注意! 這裏分別添加了 Drinks.class和Fruits.class public abstract class AppDatabase extends RoomDatabase { public abstract AllDao Dao(); private static AppDatabase mAppDataBase; public static AppDatabase getI(Context context){ //實現單例模式 if (mAppDataBase == null){ mAppDataBase = Room.databaseBuilder(context,AppDatabase.class,"data.db")//data.db 是你的數據庫名稱 .build(); } return mAppDataBase; } }
注意!請別忘記了導入數據class。我這裏分別添加了2個Drinks.class和Fruits.class
步驟四 導入數據和獲取數據
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_room); mTextView = (TextView)findViewById(R.id.textView); mBtnGetData = (Button)findViewById(R.id.btn_getdata); mBtnSetData = (Button)findViewById(R.id.btn_setdata); mBtnSetData.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { new Thread(new Runnable() { @Override public void run() { appDatabase = AppDatabase.getI(RoomActivity.this); AllDao dao = appDatabase.Dao(); dao.insert(new Drinks("肥仔快樂水"));//使用了重載方式 dao.insert(new Drinks("解奶寶礦力")); dao.insert(new Fruits("香蕉")); dao.insert(new Fruits("西瓜")); } }).start(); } }); mBtnGetData.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { new Thread(new Runnable() { @Override public void run() { final StringBuffer sb = new StringBuffer(); sb.append("數據庫內容是:"+"\n"+"-------------------------------\n"); AllDao dao = appDatabase.Dao(); List<Drinks> DrinksList = dao.getDrinksAll(); List<Fruits> FruitsList = dao.getFruitsAll(); for (Drinks drinks : DrinksList){ sb.append("Id:"+String.valueOf(drinks.id)+"\n"); sb.append("Name:"+drinks.name+"\n"); sb.append("-------------------------------\n"); } for (Fruits fruits : FruitsList){ sb.append("Id:"+String.valueOf(fruits.id)+"\n"); sb.append("Name:"+fruits.name+"\n"); sb.append("-------------------------------\n"); } runOnUiThread(new Runnable() { @Override public void run() { mTextView.setText(sb.toString()); } }); } }).start(); } }); }
效果圖:
插入 @Insert
其實@Insert能夠說明的東西很少,在上面這麼多demo演示下,你也應該明白了@Insert是幹什麼的。簡單的來講就是插入一份數據。可是固然仍是有一些東西能夠糾結的。。。
@Insert 方法的參數:
@Insert(onConflict = OnConflictStrategy.REPLACE) public abstract void insert(Fruits data); //導入單個數據 @Insert(onConflict = OnConflictStrategy.REPLACE) public abstract void insert(Fruits... data); //以數組導入數據 @Insert(onConflict = OnConflictStrategy.REPLACE) public abstract void insert(List<Fruits> data); //以list導入數據
目前,本人就驗證了這3種。第三種以list導入數據的形式。請放心,本人用demo驗證過,可使用。
@Insert 的屬性:
Insert只有一個屬性onConflict(數據衝突策略),因此我列舉一下這個屬性的值:
/** *衝突策略-替換舊數據並繼續事務。 */ int REPLACE=1; /** *衝突策略-回滾事務。 */ int ROLLBACK=2; /** *衝突策略-停止事務。 */ int ABORT=3; /** *衝突策略-使事務失敗。 */ int FAIL=4; /** *衝突策略-忽略衝突。 */ int IGNORE=5;
更新 @Update
更新@update與@Insert方法的使用方法是相似的。
@update 方法的參數 (與@Insert同樣可使用單個POJO類數據,POJO數組、POJO List,做爲參數)
@update 的屬性(與@Insert同樣使用onConflict 做爲屬性,而且屬性值徹底一致,能夠參考上面的Insert)
@Update(onConflict = OnConflictStrategy.REPLACE) public abstract void update(Fruits... data);
刪除 @Delete
刪除@Delete 就很簡單了,會根據你導入的POJO實體,去刪除表裏對應的數據列,除了基本的參數同樣能夠設置爲單個、數組、list之外,並無其餘的能夠設置的屬性了。
@Delete public abstract void delete(Fruits...data);
查詢 @Query
查詢@Query 就複雜了許多,由於涉及到了基本的SQList語法的使用。這裏我會舉例幾個經常使用的查詢語法做爲例子。
查詢數據表裏全部的數據
@Query("select * from Fruits") public abstract List<Fruits> getAll();
解釋括號中的語法:
select 表明查詢結果關鍵字,這裏寫入一個 * 星號表示咱們獲得全部表裏的數據。
from 表明從哪裏查詢,這裏咱們寫入了咱們的表名Fruits
使用上面的方法,咱們將會獲得一個表裏全部數據的List。
根據id查詢單列數據
@Query("select * from Fruits where id=:num")//根據id查找一列數據 public abstract Fruits queryId(int num);
解釋括號中的語法:
select 表明查詢結果關鍵字,這裏寫入一個 * 星號表示咱們獲得全部表裏的數據。這個與上面同樣
from 表明從哪裏查詢,這裏咱們寫入了咱們的表名Fruits。
where 表明查詢條件 這裏咱們查詢id = 下面方法輸入的值。 注意這裏的寫法 :num ,這是room特有的參數寫法,只要想要導入方法參數就須要在參數名前面添加:。
使用上面的方法,咱們將會獲得方法裏輸入參數值的對應id,列裏的全部數據。
查詢指定數據列
@Query("select id from Fruits ")//返回id字段裏的全部id值數據 public abstract int[] queryIdArray();
解釋括號中的語法:
select 表明查詢結果關鍵字,這裏寫入一個 id 星號表示咱們獲得id字段裏的全部數據。
使用上面的方法,咱們將會獲得id字段裏的全部id值
查詢數據數量
@Query("select count(*) from Fruits") public abstract int queryIsEmpty();
更多數據庫命令請查詢:https://www.runoob.com/sqlite/sqlite-tutorial.html
更新數據庫
請參考:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2017/0728/8278.html