~本特利~ |
数据库存储技术介绍
SQLite是一款轻量级的关系型数据库,它的运算速度非常快,占用资源很少,通常只需要几百KB的内存就足够了,因而特别适合在移动设备上使用。
文件存储技术和SharedPreferences存储技术只适合简单的数据和键值对。
SQLite不仅支持标准的SQL语法,还遵循了数据库的ACID事务,所以只要你以前使用过其他的关系型数据库,就可以很快地上手SQLite。而SQLite又比一般的数据库要简单得多,它甚至不用设置用户名和密码就可以使用。
Android正是把这个功能极为强大的数据库嵌入到了系统当中,使得本地持久化的功能有了一次质的飞跃。所以说Android系统是内置了数据库的!
创建数据库
Android为了让我们能够更加方便地管理数据库,专门提供了一个SQLiteOpenHelper帮助类,借助这个类可以非常简单地对数据库进行创建和升级。
1.首先SQLiteOpenHelper是一个抽象类,那就要创建一个帮助类去继承它
2.SQLiteOpenHelper中有两个抽象方法:onCreate()和onUpgrade(),我们要在帮助类里面重写这两个方法,他们分别具有实现创建和升级数据库的逻辑。
3.SQLiteOpenHelper提供了两个实例方法:getReadableDatabase()和getWritableDatabase(),都可以打开和创建现有的数据库。
4.SQLiteOpenHelper中有两个构造方法供重写,其中一个构造方法参数少一点,他接收4个参数,第一个是Context,第二个是数据库名,第三个是返回的自定义Cursor一般传入null即可,第四个是数据库版本号。
创建数据库示例写法如下:
//新建MyDatabaseHelper类继承自SQLiteOpenHelper类
class MyDatabaseHelper(val 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)"
//在onCreate中调用execSQL()方法执行语句,并弹出提示
override fun onCreate(db: SQLiteDatabase) {
db.execSQL(createBook)
Toast.makeText(context, "创建完成", Toast.LENGTH_SHORT).show()
}
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
}
}
再在布局文件中设置一个按钮:
<Button
android:id="@+id/createDatabase"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="创建数据库"
/>
在onCreate中构建一个MyDatabaseHelper对象,通过构造函数的参数将数据库指定为BookStore.db,版本号为1,点击上面创建的按钮,setOnClickListener监听器会调用getWritableDatabase()完成创建。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val dbHelper = MyDatabaseHelper(this, "BookStore.db", 1)
createDatabase.setOnClickListener {
dbHelper.writableDatabase
}
}
}
提醒一下:SQLite中数据类型有integer整型,real浮点型,text文本类型,blob二进制类型。
需要下载Database Navigator插件就可以看到数据库里的表了。
升级数据库
onUpgrade()方法是用于对数据库进行升级的,它在整个数据库的管理工作当中起着非常重要的作用。
示例写法如下:
class MyDatabaseHelper(val context: Context, name: String, version: Int) : SQLiteOpenHelper(context, name, null, version) {
…
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)
Toast.makeText(context, "创建完成", Toast.LENGTH_SHORT).show()
}
//将已经存在的表删除,再调用 onCreate(db)重新创建
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()能够执行,在参数里将版本号改为一个比之前大的数,比如2。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val dbHelper = MyDatabaseHelper(this, "BookStore.db", 2)
createDatabase.setOnClickListener {
dbHelper.writableDatabase
}
}
}
版本号2就是表示对数据库进行了升级
添加数据
SQLiteDatabase中提供了一个insert() 方法,专门用于添加数据。
它接收3个参数:
第一个参数是表名,我们希望向哪张表里添加数据,这里就传入该表的名字;
第二个参数用于在未指定添加数据的情况下给某些可为空的列自动赋值NULL,一般我们用不到这个功能,直接传入null即可;
第三个参数是一个ContentValues对象,它提供了一系列的put()方法重载,用于向ContentValues中添加数据,只需要将表中的每个列名以及相应的待添加数据传入即可。
示例写法如下:
我们先在布局文件中设置一个按钮:
<Button
android:id="@+id/addData"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="添加数据"
/>
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//在onCreate中构建一个MyDatabaseHelper对象,通过构造函数的参数将数据库指定为BookStore.db,版本号为2,点击上面创建的按钮,setOnClickListener监听器会调用getWritableDatabase()完成创建。
val dbHelper = MyDatabaseHelper(this, "BookStore.db", 2)
createDatabase.setOnClickListener {
dbHelper.writableDatabase
}
...
addData.setOnClickListener {
val db = dbHelper.writableDatabase
val values1 = ContentValues().apply {
// 开始组装第一条数据
put("name", "学习android的笔记")
put("author", "本特利")
put("pages", 454)
put("price",29.9)
}
db.insert("Book", null, values1) // 插入第一条数据
val values2 = ContentValues().apply {
// 开始组装第二条数据
put("name", "Android也不是很难")
put("author", "本特利")
put("pages", 510)
put("price", 29.8)
}
db.insert("Book", null, values2) // 插入第二条数据
}
点击按钮完成插入后,同样通过Database Navigator插件双击表名就可以查看了
更新数据
SQLiteDatabase中提供了一个非常好用的**update()**方法,用于对数据进行更新。
这个方法接收4个参数:
第一个参数和insert()方法一样,也是表名,指定更新哪张表里的数据;
第二个参数是ContentValues对象,要把更新数据在这里组装进去;
第三、第四个参数用于约束更新某一行或某几行中的数据,不指定的话默认会更新所有行。
示例写法如下:
先添加一个按钮:
<Button
android:id="@+id/updateData"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="更新数据"
/>
在上面的MainActivity中添加:
...
//在点击事件里构建一个ContentValues对象,把价格这行数据更新为10.99
updateData.setOnClickListener {
val db = dbHelper.writableDatabase
val values = ContentValues()
values.put("price", 10.99)
//然后调用update方法执行具体的更新,第三第四个参数用来指定具体更新哪行,第三个参数对应的是SQL语句的where部分,表示更新所有name 等于?的行,而?是一个占位符,可以通过第四个参数提供的一个字符串数组为第三个参数中的每个占位符指定相应的内容
val rows = db.update("Book", values, "name = ?", arrayOf("学习android的笔记"))
}
array0f()方法是Kotlin提供的一种用于便捷创建数组的内置方法。
删除数据
SQLiteDatabase中提供了一个delete()方法,专门用于删除数据。
这个方法接收3个参数:
第一个参数仍然是表名,这个没什么好说的;
第二、第三个参数用于约束删除某一行或某几行的数据,不指定的话默认会删除所有行。
示例写法如下:
同样我们先把按钮设置好:
<Button
android:id="@+id/deleteData"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="删除数据"
/>
跟着在前面的MainActivity代码中加入:
...
deleteData.setOnClickListener {
val db = dbHelper.writableDatabase
db.delete("Book", "pages > ?", arrayOf("500"))
}
可按钮的点击事件里指明删除Book中的数据,并目通过第二、第三个参数来指定仅删除那些页数超过500页的书。
查询数据
SQLiteDatabase中还提供了一个query() 方法用于对数据进行查询。这个方法的参数非常复杂,最短的一个方法重载也需要传入7个参数。
参数的详细解释见下表:
查询Book表中所有数据的示例写法:
照旧设置一个按钮:
<Button
android:id="@+id/queryData"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="查询数据"
/>
val dbHelper = MyDatabaseHelper(this, "BookStore.db", 2)
val db = dbHelper.writableDatabase
// 查询Book表中所有的数据,只使用了第一个参数指明查询Book表,后面的参数全部为null。这就表示希望查询这张表中的所有数据,虽然这张表中目前只剩下一条数据了。
val cursor = db.query("Book", null, null, null, null, null, null)
//调用它的moveToFirst()方法,将数据的指针移动到第一行的位置,然后进入一个循环当中,去遍历查询到的每一行数据
if (cursor.moveToFirst()) {
do {
// 遍历Cursor对象,在这个循环中可以通过Cursor的 getColumnIndex()方法获取某一列在表中对应的位置索引,然后将这个索引传入相应的取值方法中,就可以得到从数据库中读取到的数据了
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"))
//接着我们使用Log将取出的数据打印出来,借此检查读取工作有没有成功完成
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()
使用SQL操作数据库
添加数据的方法如下:
db.execSQL(
“insert into Book (name, author, pages, price) values(?, ?, ?, ?)”, arrayOf("The Da Vinci Code", "Dan Brown", "454", "16.96")
)
更新数据的方法如下:
db.execSQL("update Book set price = ? where name = ?", arrayOf("10.99", "The Da Vinci Code"))
删除数据的方法如下:
db.execSQL("delete from Book where pages > ?", arrayOf("500"))
查询数据的方法如下:
val cursor = db.rawQuery("select * from Book", null)