准备知识:
- 对关系型数据库有初步了解
- 会写基本的SQL语句来管理数据库
一 什么是持久化:
- 瞬时状态:数据存储在内存,可能会因为程序关闭或其他原因导致内存被回收而丢失数据
- 持久状态:瞬时状态的数据已被保存到存储介质中,不随程序关闭而丢失
android提供了3种方式实现数据持久化:
- SharedPerference
- 文件存储
- SQLite数据库
本文主要介绍使用SQLite数据库实现数据持久化
二 SQLite
2.1 简介:
- 是一款轻量级的关系型数据库,它的运行速度快,占用资源少。因而特别适合在移动设备上使用。
- 不仅支持标准的SQL语法,而且遵循数据库事务管理
2.2 使用:
下面我们以用数据库记录APP的用户信息为例看看如何使用SQLiteOpenHelper:
Android 给出了帮助使用该数据库的类: SQLiteOpenHelper
我们创建一个类继承SQLiteOpenHelper来帮助使用数据库。
class MySQLiteHelper(context:Context) : SQLiteOpenHelper(context,DATABASE_NAME,null,DATABASE_VERSION) {
//第一次创建该类时,调用的方法
override fun onCreate(db:SQLiteDatabase) {
db.execSQL(INIT_SENTENCE)
}
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
// 删除旧表
db?.execSQL("DROP TABLE IF EXISTS User")
// 创建新表(根据您的 INIT_SENTENCE)
db?.execSQL(INIT_SENTENCE)
}
//传入用户类,在数据库中添加用户
fun addUser(user: User) :Long{
val values = ContentValues()
values.put("account_num",user.getAccountNum())
values.put("userName", user.getUserName())
values.put("pwd", user.getPassword())
values.put("age",user.getAge())
values.put("email",user.getEmail())
values.put("self_introduction",user.getSelfDescr())
values.put("head_image",user.getHeadImage())
val db = this.writableDatabase
val success = db.insert("User", null, values)
values.clear()
db.close()
return success
}
//根据账号查找用户,并返回User类型
fun queryByAccount_num(account_num:String):User? {
val query = "SELECT * FROM User WHERE account_num = ?"
val db = this.readableDatabase
val cursor = db.rawQuery(query, arrayOf(account_num))
//注意判断查询结果是否为空不能使用 cursor==/!=null
//可以使用moveToFirst()方法,当查询结果为空时该方法会返回false
if (cursor.moveToFirst()) {
val account_num_r = cursor.getString(cursor.getColumnIndexOrThrow("account_num"))
val username_r = cursor.getString(cursor.getColumnIndexOrThrow("userName"))
val pwd_r = cursor.getString(cursor.getColumnIndexOrThrow("pwd"))
val age_r = cursor.getInt(cursor.getColumnIndexOrThrow("age"))
val email_r = cursor.getString(cursor.getColumnIndexOrThrow("email"))
val self_intro_r = cursor.getString(cursor.getColumnIndexOrThrow("self_introduction"))
val head_image_r = cursor.getBlob(cursor.getColumnIndexOrThrow("head_image"))
cursor.close()
return User(account_num_r, username_r, pwd_r, age_r, email_r,self_intro_r,head_image_r)
} else {
return null
}
}
//更新用户信息
fun updateUserInfo(account_num: String,user_name:String,age:Int,email:String,self_description:String){
println("user_name=$user_name,age = $age,email:$email,self_introduction:$self_description")
val db = this.writableDatabase
val values = ContentValues()
values.put("userName",user_name)
values.put("age",age)
values.put("email",email)
values.put("self_introduction",self_description)
val whereClause = "account_num = ?"
val whereArgs = arrayOf(account_num)
db.update("User", values, whereClause, whereArgs)
prtUsers()
values.clear()
db.close()
}
fun getNum():Int {
val query = "SELECT COUNT(*) FROM User"
val db = this.readableDatabase
val cursor = db.rawQuery(query, null)
var recordCount = 0
if (cursor.moveToFirst()) {
recordCount = cursor.getInt(0) // 获取第一列的值(记录数量)
}
cursor.close()
db.close()
return recordCount
}
fun clearUsers(){
val db = this.writableDatabase
db.delete("User", null, null) // 删除 User 表中的所有数据
db.close()
}
companion object{
const val DATABASE_NAME = "Wandu.db" //数据库名称
const val DATABASE_VERSION = 2 //数据库版本
//初始化时的SQL语句
const val INIT_SENTENCE =
"CREATE TABLE User ("+
"id INTEGER PRIMARY KEY AUTOINCREMENT,"+
"account_num TEXT UNIQUE,"+
"pwd TEXT NOT NULL,"+
"userName TEXT NOT NULL,"+
"age INTEGER DEFAULT 0," +
"email TEXT," +
"self_introduction TEXT," +
"head_image BLOB" +
")";
}
}
其中:
2.2.1. onCreat(db:SQLiteDatabase)方法:
如果数据库中没有任何内容会调用该方法,该方法完成新建数据库时的初始化行为:
db.execSQL(INIT_SENTENCE)
INIT_SENTENCE是一个SQL语句,创建一个名叫User的table,该表格具有id,account_num,pwd,userName,age,email等属性
ecexSQL(str)则是让数据库处理SQL语句str
2.2.2 onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int)方法:
数据库更新时会调用的方法
2.2.3.getReadableDatabase()和getWritableDatabase()方法:
返回一个SQLiteDatabase对象,借助这个对象就可以对数据进行增删改查操作
其中增删改使用**getWritableDatabase()方法得到可以写的数据库
查操作只需使用getReadableDatabase()**方法得到可以读的数据库即可
2.3SQLiteDatabase类
2.3.1. 添加:insert()方法:
接收三个参数:
- 第一个:表名,要操作的表
- 第二个:null,在未指定添加数据的情况下给某些可为空的列自动赋值NULL
- 第三个:要添加的数据,是一个ContentValues对象
- ContentValues使用put设置响应属性的值
put()方法的第一个参数是属性名(也是table对应的列名),第二个参数是相应的属性值 - 在设置完属性值后,再调用insert方法将contentValue插入表格
- 如果要用同一个ContentValue实例连续insert两个数据,记得在第一次insert后将调用contentValue的insert方法
- ContentValues使用put设置响应属性的值
可参考addUser()方法中的代码:
//传入用户类,在数据库中添加用户
fun addUser(user: User) :Long{
val values = ContentValues()
values.put("account_num",user.getAccountNum())
values.put("userName", user.getUserName())
values.put("pwd", user.getPassword())
values.put("age",user.getAge())
values.put("email",user.getEmail())
values.put("self_introduction",user.getSelfDescr())
values.put("head_image",user.getHeadImage())
val db = this.writableDatabase
val success = db.insert("User", null, values)
values.clear()
db.close()
return success
}
2.3.2. 查询:
rawQuery()方法:
返回一个Cursor对象,查询到的所有数据从这个对象中取出
- 第一个参数:一个sql语句
- 第二个参数:一个list,用于“代替”sql中的 ‘?’.
val query = "SELECT * FROM User WHERE account_num = ?"
val db = this.readableDatabase
val cursor = db.rawQuery(query, arrayOf(account_num))
这里的Where部分的意思是:
当表格中数据的account_num属性值为arrayOf(account_num)中的某一个时
给段实例代码:这段代码实现了根据account_num(账号)去数据库中查询取出数据,并由这些数据新建一个User类并返回
//根据账号查找用户,并返回User类型
//根据账号查找用户,并返回User类型
fun queryByAccount_num(account_num:String):User? {
val query = "SELECT * FROM User WHERE account_num = ?"
val db = this.readableDatabase
val cursor = db.rawQuery(query, arrayOf(account_num))
//注意判断查询结果是否为空不能使用 cursor==/!=null
//可以使用moveToFirst()方法,当查询结果为空时该方法会返回false
if (cursor.moveToFirst()) {
val account_num_r = cursor.getString(cursor.getColumnIndexOrThrow("account_num"))
val username_r = cursor.getString(cursor.getColumnIndexOrThrow("userName"))
val pwd_r = cursor.getString(cursor.getColumnIndexOrThrow("pwd"))
val age_r = cursor.getInt(cursor.getColumnIndexOrThrow("age"))
val email_r = cursor.getString(cursor.getColumnIndexOrThrow("email"))
val self_intro_r = cursor.getString(cursor.getColumnIndexOrThrow("self_introduction"))
val head_image_r = cursor.getBlob(cursor.getColumnIndexOrThrow("head_image"))
cursor.close()
return User(account_num_r, username_r, pwd_r, age_r, email_r,self_intro_r,head_image_r)
} else {
return null
}
}
- 对于查询结果是否为空的判断,不能判断cursor是否为null,直接使用cursor的moveToFirst();在方法在移到cursor的最前面的同时,返回boolean类型,当查询结果为空,会返回false
- 从cursor中获得查询结果:
会使用形如cursor.getType(cursor.getColumnIndexOrThrow(column_name))的调用:
- column_name:是要取的属性值在表中的属性名
- getType()实则是根据要取出的属性类型选择方法:例如要取出的类型是String就是getString()方法
2.3.3. 更新:update()方法:
四个参数:
- table:要更新的表名
- value:要更新的数据
- whereClause:要更新哪行的数据
- whereArgs:上一个参数中占位符的值
- 与insert方法一样,value的类型是ContentValue;在updata前首先准备好value,可以使用put方法,对于updata方法使用的ContentValue,只需要put要更新的属性名和属性值即可
- 第三四个参数用于完成删选条件,
2.3.4. 删除:delete()方法:
三个参数:
- table:要更新的表名
- whereClause:约束要删除哪行的数据
- whereArgs:上一个参数中占位符的值
参考clearUsers()方法:
这里的delete()方法第2、3个参数,均为null,说明没有限制,即删除所有User表格中数据
fun clearUsers(){
val db = this.writableDatabase
db.delete("User", null, null) // 删除 User 表中的所有数据
db.close()
}