欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-03-09 21:04:51
...

目录

 

简介

导入工程

使用流程概况

一个简单的小Demo

深入学习 @Entity使用

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

主键 @PrimaryKey

索引 @Index

外键 @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();
            }
        });
    }
}

以上是创建数据库、插入数据、查询数据在线程中的操作。创建数据库、插入数据和查询数据最好都在子线程里操作,尽量不要在主线程里操作数据库。另外注意!如果你在子线程里创建了数据库,那么你在主线程中就无法获取数据,一定要在子线程里获取数据。

效果图:

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

 

深入学习 @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插入方法里写的是数组参数,所以也可以多个添加

效果图:

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

组合主键  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代码就已经贴全了。

效果图:

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

外键的功能探索:

约束:

或许某些同学会这么有这些疑问,ヾ(。`Д´。) 看到目前为止外键好像并没有什么用啊。恩,这是我一开始的疑惑,特别是我发现还需要手动添加外键(原谅我之前没有接触过数据库),这不是鸡肋么。下面,我们就来演示外键的功能之一”约束“。

                        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 开发 框架系列 Google的ORM框架 Room

恩,报错了。我们看看,为什么报错了?

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的列,然后在删除这个列(删除的方法请向上看之前的代码),然后在分别读出数据库里的数据。

效果图:

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

删除了主键书架里,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();
            }
        });
    }
}

效果图:

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

深入学习@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();
            }
        });
    }

效果图:

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

插入 @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;

使用方式上方的demo已经演示了很多次了,但是我这边还是贴出来一下:

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    public abstract void insert(Fruits... data);

更新 @Update

 

 

 

删除 @Delete

 

 

查询 @Query

 

 

 

相关标签: android