数据库从sqlite开始

 

论SQLite的操作

ROOM是谁,我在哪,我的大脑呢

操作基本靠exeSQL(就是直接用SQL

SQL是不分大小写的

有时工具不一定靠谱,真正重要的是靠自己的判断

省流


  通过API 通过SQL
增表   create table 表名 (一堆值的名及[类型])
增数据 db.insert(表名, null, 值) insert into 表名 (键) values(值)
删表   drop table [条件] 表名
删数据 db.delete("表名, 条件", 条件的值) delete from 表名 where 条件
db.update(表名, 要修改的列, 条件), arrayOf(值) update 表名 set 列名 = ? where 条件
db.query(表名, 列名, 条件, 条件中的具体值, 要分组的列, 分组的筛选条件, 搜索结果的排序方式) select 列名 from 表名 where 条件 ……

首先

操作数据库那就得先有一个,原始的办法是弄个SQLiteOpenHelper,比如下面这样

class NoteDatabaseHelper(val context: Context, name: String, version: Int) :
SQLiteOpenHelper(context, name, null, version)

这样在别的文件中,可以通过两行代码来用这个Helper

val dbHelper = NoteDatabaseHelper(context, "数据库名", 版本)
val db = dbHelper.writableDatabase

这个db就是可以操作的数据库了

增(insert)

创建一个新表可以像下面这样:

create table Note (
        id integer primary key autoincrement,
        title text,
        content text,
        editTime)

也就是create table 表名 (一堆值的名及类型(可选))

如果想要默认值,可以在类型后面加上NOT NULL DEFAULT 默认值

往表里面插入新的数据如下

val value = ContentValues().apply {
    put("title", binding.titleBox.text.toString())
    put("content", binding.editBox.text.toString())
    put("editTime", System.currentTimeMillis())
}
db.insert("Note", null, value)

在kt里面可以这样组装一个数据再插入,插入不过就是db.insert(表名, null, 值)

除此之外,插入还可以用insertWithOnConflict,用来处理可能出现的冲突,只要在最后多加一个参数,比如

db.insertWithOnConflict("word", null, values, SQLiteDatabase.CONFLICT_IGNORE) // 忽略相同id

这样就是当主键冲突时忽略然后继续插入

直接用SQL那就是insert into 表名 (键) values(值)后面再填值,例如

db.execSQL("insert into Book (name, author, pages, price) values(?, ?, ?, ?)", 
    arrayOf("The Da Vinci Code", "Dan Brown", "454", "16.96") 
) 

看得出来一个?对应一个值

删(delete)

就是db.delete("表名, 条件", 条件的值),比如

db.delete("Book", "pages > ? ", arrayOf("500"))

用SQL则是delete from 表名 where 条件,后面跟上一串条件,如

db.execSQL("delete from Book where pages > ?", arrayOf("500")) 

删表则是drop table [条件] 表名 ,像是

drop table Note

改(update)

修改数据用的是update,像db.update("Book", values, "name = ?", arrayOf("The Da Vinci Code"))

db.update(表名, 要修改的列, 条件), arrayOf(值),其中要修改的列和条件和值都可以不止一个

用SQL就变成了

update 表名 set 列名 = ? where 条件

后面一样用arrayOf填入值即可

查(select/query)

查可麻烦了,有一大堆参数

db.query(表名, 列名, 条件, 条件中的具体值, 要分组的列, 分组的筛选条件, 搜索结果的排序方式)

如果换成用参数名表示就是

db.query(table, columns, selections, selectionArgs, groupBy, having, orderBy)

使用having时必须也要有groupBy否则会狠狠报错

一般情况下都是用不到那么多个参数的,所以不要的地方用null填满就好了,比如

val cursor = db.query("Book", null, null, null, null, null, null)

用SQL上面这句可以简化成

val cursor = db.rawQuery("select * from Book", null) 

要一行一行查询数据可以这样

if (cursor.moveToFirst()) {
    do {
    val name = cursor.getString(cursor.getColumnIndex("name"))
    val author = cursor.getString(cursor.getColumnIndex("author"))
    val pages = cursor.getInt(cursor.getColumnIndex("pages"))
    val price = cursor.getDouble(cursor.getColumnIndex("price"))
    } while (cursor.moveToNext())
}
cursor.close() // 最后别忘了关掉

不过用getColumnIndexOrThrow比用getColumnIndex要更安全,不然有可能直接得到-1崩掉

在查询数据时一定要先用moveToFirst()转到第一个符合条件的数据,不然会狠狠地报错!

有关更多SQL语句

id BETWEEN A AND B可以查询所有符合A≤id≤B的行

DESC代表倒序查找

事务(transaction)

事务让一组操作只有全部执行完才会生效,有一个操作失败了就要全部打回

通过db.beginTransaction()就可以开启一个事务了

db.setTransactionSuccessful()说明事务完成,而db.endTransaction()代表事务结束

显然如果事务不完成那即使结束了前面对数据库的操作会全部木大

可以像下面这样用事务

db.beginTransaction()
try{
	...
    db.setTransactionSuccessful()
} catch (...) {
	...
} finally {
    db.endTransaction()
}

好耶!这样SQLite的基础操作就学完了,接下来的步骤是……学别的数据库框架,然后就不用这些语法了?!

不过那些框架都是基于SQLite写的,至少能知道面对的是个啥罢

下一集:LitePal我来辣!

下下一集:解析失败重回SQLite