概述
SQLite 是一款轻量级的关系型数据库,它的运算速度非常快,占用资源非常少,因此特别适合在移动设备使用。SQLite 不仅支持标准的 SQL 语法,还遵循数据库的 ACID 事务。而 SQLite 又比一般的数据库要简单许多,甚至不需要设置用户名和密码就可以使用
创建数据库
Android 提供了一个 SQLiteOpenHelper 帮助类,用以对数据库进行创建和升级。
SQLiteOpenHelper 是一个抽象类,有两个抽象方法:onCreate()
和 onUpgrade()
,我们需要重写这两个方法,然后分别在这两个方法中实现创建和升级数据库的逻辑
class MyDatabaseHelper(context: Context?, name: String?, version: Int) : SQLiteOpenHelper(context, name, null, version) {
private val createBook = "create table Book (" +
"id integer primary key autoincrement," +
"author text," +
"price real," +
"pages integer," +
"name text)"
override fun onCreate(db: SQLiteDatabase) {
db.execSQL(createBook)
}
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
}
}
可以看到,我们把建表语句定义成一个字符串变量,然后在 onCreate()
方法中调用 SQLiteDatabase
的 execSQL()
方法去执行这条建表语句
我们在创建一个按钮,并为其添加点击事件
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val dbHelper = MyDatabaseHelper(this, "Book.db", 1)
createDatabase.setOnClickListener {
dbHelper.writableDatabase
}
}
}
在 onCreate()
方法中构建一个 MyDatabaseHelper
对象,并通过构造函数将数据库名指定为 Book.db,版本号指定为 1,然后在按钮点击事件里调用 getWritableDatabase()
方法。当第一次点击时,会检查当前程序中并没有 Book.db 这个数据库,于是就会调用 MyDatabaseHelper
的 onCreate()
方法创建表。再次点击,因为数据库已经存在,就不会重复创建
升级数据库
目前我们的数据库里有一张 Book 表,如果我们想再添加一张 Category 表的话,不能像创建数据库一样直接执行 onCreate()
方法,因为数据库已经存在了。这时候就必须借助 onUpgrade()
方法
class MyDatabaseHelper(context: Context?, name: String?, version: Int) : SQLiteOpenHelper(context, name, null, version) {
private val createBook = "create table Book (" +
"id integer primary key autoincrement," +
"author text," +
"price real," +
"pages integer," +
"name text)"
private val createCategory = "create table Category (" +
"id integer primary key autoincrement," +
"category_name text," +
"category_code integer)"
override fun onCreate(db: SQLiteDatabase) {
db.execSQL(createBook)
db.execSQL(createCategory)
}
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
db.execSQL("drop table if exists Book")
db.execSQL("drop table if exists Category")
onCreate(db)
}
}
我们在 onUpgrade()
方法执行了两条 DROP 语句,然后再调用 onCreate()
方法重新创建。为了让 onUpgrade()
方法执行,我们需要传入比当前版本大的数,之前传的是 1,现在传入 2,就能执行了
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val dbHelper = MyDatabaseHelper(this, "Book.db", 2)
createDatabase.setOnClickListener {
dbHelper.writableDatabase
}
}
}
增删改查
Android 提供了一系列辅助方法,让你不用编写 SQL 也能完成 CRUD 操作
1. 添加数据
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val dbHelper = MyDatabaseHelper(this, "Book.db", 2)
...
addData.setOnClickListener {
val db = dbHelper.writableDatabase
val values = ContentValues().apply {
// 组装数据
put("name", "The Da Vinci Code")
put("author", "Dan Brown")
put("pages", 454)
put("price", 16.96)
}
// 参数说明:
// 1. 表名
// 2. 用于在未指定添加数据的情况下给某些可为空的列自动赋值 NULL
// 3. ContentValues 对象
db.insert("Book", null, values)
}
}
2. 更新数据
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val dbHelper = MyDatabaseHelper(this, "Book.db", 2)
...
updateData.setOnClickListener {
val db = dbHelper.writableDatabase
val values = ContentValues()
values.put("price", 16.96)
// 参数说明:
// 1. 表名
// 2. ContentValues 对象,把更新数据组装进去
// 3、4. 用于约束更新某一行或某几行的数据,不指定默认更新所有行
db.update("Book", values"name = ?", arrayOf("The da Vinci Code"))
}
}
3. 删除数据
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val dbHelper = MyDatabaseHelper(this, "Book.db", 2)
...
deleteData.setOnClickListener {
val db = dbHelper.writableDatabase
// 参数说明:
// 1. 表名
// 2、3. 用于约束删除某一行或某几行的数据,不指定默认删除所有行
db.delete("Book","pages > ?", arrayOf("500"))
}
}
4. 查询数据
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val dbHelper = MyDatabaseHelper(this, "Book.db", 2)
...
queryData.setOnClickListener {
val db = dbHelper.writableDatabase
// 参数说明
// 1. 指定查询的表名
// 2. 指定查询的列名
// 3. 指定 where 约束条件
// 4. 为 where 中占位符提供具体的值
// 5. 指定需要 group by 的列
// 6. 对 group by 的结果进一步约束
// 7. 指定查询结果的排序方式
val cursor = db.query("Book", null, null, null, null, null, null)
if (cursor.moveToFirst()) {
do {
// 遍历 Cursor 对象,取出数据并打印
val name = cursor.getString(cursor.getColumnIndex("name"))
val author = cursor.getString(cursor.getColumnIndex("author"))
val pages = cursor.getString(cursor.getColumnIndex("pages"))
val price = cursor.getString(cursor.getColumnIndex("price"))
Log.d("MainActivity", "book name is $name")
Log.d("MainActivity", "book author is $author")
Log.d("MainActivity", "book pages is $pages")
Log.d("MainActivity", "book price is $price")
} while (cursor.moveToNext())
}
cursor.close()
}
}
除了使用 Android 提供的 API,我们也可以自己编写 SQL 语句去执行
// 参数处写 SQL 语句
db.execSQL("......")
使用事务
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val dbHelper = MyDatabaseHelper(this, "Book.db", 2)
...
replaceData.setOnClickListener {
val db = dbHelper.writableDatabase
// 开启事务
db.beginTransaction()
try {
db.delete("Book", null, null)
if (true) {
// 手动抛出异常,让事务失败
throw NullPointerException()
}
val values = ContentValues().apply {
put("name", "Game of Thrones")
put("author", "George Martin")
put("pages", 720)
put("price", 20.85)
}
db.insert("Book", null, values)
// 事务已经成功执行
db.setTransactionSuccessful()
} catch (e: Exception) {
e.printStackTrace()
} finally {
// 结束事务
db.endTransaction()
}
}
}