1.引言
Sqlite的代码写起来繁琐且容易出错,数据和对象之间的映射过程写起来实在无趣,还是不如使用ORM框架来的得心应手。
2.Room是什么
Room是Goole推出的数据库框架,属于ORM库。
Room提供了SQLite的抽象层,以便在充分利用SQLite的同时允许流畅的数据库访问。
Room与其他ORM框架对比有以下优点:
- 编译期检查,Room会在编译的时候验证每个
@Query和@Entity等,它不仅检查语法问题,还会检查是否有该表,这就意味着几乎没有任何运行时错误的风险 - 较少的模板代码
- 与 LiveData集成
Room有3个主要组件:
- Entity : 数据实体,对应数据库中的表
- DAO:数据访问对象,包含访问数据库的方法
- Database:数据库持有者。
Room的架构图:
3.Room使用
在project的build.gradle中加入google的Maven仓库(高版本的AS自动添加):
allprojects {
repositories {
google()
}
}
在app的build.gradle中添加依赖:
apply plugin: 'kotlin-kapt'
dependencies {
def room_version = "2.2.5"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
}
至此,Room就已经导入进来了。
1.Entity(创建表)
@Entity(tableName = "Book")
class Book{
@PrimaryKey()
var id :Int = 0
@ColumnInfo(name = "book_name")
var bookName:String? = null
var isbn:String? = null
var anchor:String? = null
@Ignore
var price :Int = 0
override fun toString(): String {
return "Book(id=$id, bookName=$bookName, isbn=$isbn, anchor=$anchor, price=$price)"
}
}
创建表一般会用到下面几个注解:
@Entity(tableName=“表名称”)
定义一个表
@PrimaryKey(autoGenerate=true)
定义主键
@ColumnInfo(name = “列名”)
定义列名
@Ignore
忽略某个字段
2.Dao
@Dao
abstract class BookDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun insert(book: Book)
@Delete
abstract fun delete(book:Book)
@Update
abstract fun update(book:Book)
@Query("select * from Book where id =:id")
abstract fun queryById(id:Int) : Book
@Query("select * from Book")
abstract fun queryAll():List<Book>
}
@Insert、@Delete、@Update、@Query 代表我们常用的插入、删除、更新、查询数据库操作。
Dao非常的灵活,你可以传入不同的参数,像这样:
@Insert
abstract fun insert(books:List<Book>)
@Delete
abstract fun delete(vararg books: Book)
当然,你也可以返回不同的类型,例如:
@Query("select book_name from Book")
abstract fun queryAllBookName() : List<String?>
@Query("select count(*) from Book")
abstract fun bookCount() : Int
@Query非常的强大,你可以编写任意sql语句并得到你想要的结果。
3.DataBase
@Database(entities = [Book::class],version = 1)
abstract class AppDatabase : RoomDatabase(){
abstract fun bookDao(): BookDao
}
创建好这三个组件,Room的配置基本就已经完成了,通常我们需要的业务逻辑都加写在Dao中的抽象方法中。
点击Build编译项目,Room会自动生成对应的实现类。验证上面的代码:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val appDb = Room.databaseBuilder(this, AppDatabase::class.java, "myDb.db")
.allowMainThreadQueries()
.build()
val bookDao = appDb.bookDao()
val ludingji = Book()
ludingji.id = 1
ludingji.bookName = "《鹿鼎记》"
val tianlongbabu = Book()
tianlongbabu.id = 2
tianlongbabu.bookName = "《天龙八部》"
bookDao.insert(ludingji)
bookDao.insert(tianlongbabu)
Log.d("MainActivity",bookDao.queryAll().toString())
Log.d("MainActivity",bookDao.queryById(1).toString())
bookDao.delete(ludingji)
Log.d("MainActivity",bookDao.queryAll().toString())
tianlongbabu.anchor = "金庸"
bookDao.update(tianlongbabu)
Log.d("MainActivity",bookDao.queryById(2).toString())
}
//输出结果:
//[Book(id=1, bookName=《鹿鼎记》, isbn=null, anchor=null, price=0), Book(id=2, bookName=《天龙八部》, isbn=null, anchor=null, price=0)]
//[Book(id=2, bookName=《天龙八部》, isbn=null, anchor=null, price=0)]
//Book(id=1, bookName=《鹿鼎记》, isbn=null, anchor=null, price=0)
//Book(id=2, bookName=《天龙八部》, isbn=null, anchor=金庸, price=0)
}
4.数据库迁移
在Room中,数据库迁移使用的是Migration对象,定义如下:
public abstract class Migration {
public final int startVersion;
public final int endVersion;
public Migration(int startVersion, int endVersion) {
this.startVersion = startVersion;
this.endVersion = endVersion;
}
public abstract void migrate(@NonNull SupportSQLiteDatabase database);
}
startVersion是旧版本号,endVersion是新版本号。数据库版本发生变更(如升级)会回调migrate函数,我们需要在此回调中编写版本变更的相关代码,例如创建表、添加列等等。
把Migration添加到对应的db中:
val appDb = Room.databaseBuilder(this, AppDatabase::class.java, "myDb.db")
.allowMainThreadQueries()
.addMigrations(object : Migration(1,2){
override fun migrate(database: SupportSQLiteDatabase) {
//升级相关操作
}
})
.build()
5.数据库记录
Room提供了记录每个版本数据库信息的方式:
defaultConfig {
//...
javaCompileOptions {
annotationProcessorOptions {
arguments += ["room.schemaLocation": "$projectDir/schemas".toString()]
}
}
}
编译后,会在对应路径生成schemas文件夹:
1.json中的1表示版本号,json包含了各个版本的概要,表结构等信息:
{
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "5d16d39b710ef34dd63824a76d120e02",
"entities": [
{
"tableName": "Book",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `book_name` TEXT, `isbn` TEXT, `anchor` TEXT, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "bookName",
"columnName": "book_name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "isbn",
"columnName": "isbn",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "anchor",
"columnName": "anchor",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '5d16d39b710ef34dd63824a76d120e02')"
]
}
}
3.总结
文章描述了Room的基本用法,更多请参考官方文档:
更多安卓知识体系,请关注公众号: