Android 开发 框架系列 Google的ORM框架 Room


目录html

 

简介java

导入工程android

使用流程概况sql

一个简单的小Demo数据库

深刻学习 @Entity使用数组

自定义表名 tableName  自定义字段名@ColumnInfoapp

主键 @PrimaryKey框架

索引 @Indexide

外键 @ForeignKey学习

嵌入对象 @Embedded

深刻学习@Dao

建立Dao Class

插入 @Insert


简介

 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"

使用流程概况

由于建立步骤较多因此这里简单先给一个流程,给你们有一个简单的概念:

  1. 建立数据class,使用的注释是:@Entity
  2. 建立Dao 数据操做抽象class,使用的注释是:@Dao(负责提供操做数据的方法,好比基本的增长、更新、查找、删除。固然除了这些基本的,更复杂的咱们将在后续深刻学习)
  3. 建立应用程序数据库的抽象class,使用的注释是:@Database(负责建立应用数据库,组合“数据class”与“数据操做class”,还有数据库版本)
  4. 实例化使用数据库

一个简单的小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