Android SQLite数据库

2022-01-13 14:36:10 浏览数 (1)

创建数据库

SQLiteOpenHelper 抽象类有两个抽象方法:onCreate() onUpgrade() 创建和升级数据库

实例方法:getReadableDatabase() getWritableDatabase()。这两个方法都可以创建或打开一个现有的数据库,并返回一个可对数据库进行读写操作的对象。 区别为:当数据库不可写入时getReadDatabase()返回的对象将以只读的方式打开,getWritableDatabase()则出现异常。

SQLiteOpenHelper中有两个构造方法可提供重写,一般使用参数较少的构造方法即可。 参数: Context; 数据库名; Cursor:允许我们在查询数据的时候返回一个自定义的Cursor,一般传null; 当前数据库的版本号:可用于对数据库进行升级操作。

构造出SQLite实例后,在调用它的getReadableDatabase()或getWritableDatabase()方法就能创建数据库了,数据库文件会存放在/data/data/<package name>/databases/目录。此时,重写的onCreate()方法也会得到执行,所以通常会在这里处理一些创建表的逻辑。

例子练习: 创建一个DatabaseTest项目 创建一个名为BookStore.db的数据库,然后在这个数据库中新建一张Book表,表中有id(主键)、作者、价格、页数和书名等列

代码语言:javascript复制
create table Book {
    id integer primary key autoincrement,
    author text,
    price real,
    pages integer,
    name text }

integer 整型; real 浮点型; text 文本类型; blob 二进制类型; 使用primary key将id列设为主键,并用autoincrement表示id是自增长的。

新建MyDatabaseHelper类继承自SQLiteOpenHelper:

代码语言:javascript复制
package com.example.databasetest

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.widget.Toast

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)"

    override fun onCreate(db: SQLiteDatabase?) {
        db?.execSQL(createBook)
        Toast.makeText(context, "Create succeeded", Toast.LENGTH_SHORT).show()
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
        TODO("Not yet implemented")
    }
}

在onCreate()方法中调用SQLiteDatabase的execSQL()方法去执行这条建表语句,并弹出一个Toast提示创建成功。

修改activity_main.xml中的代码:

代码语言:javascript复制
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >
    
    <Button
        android:id="@ id/createDatabase"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Create Database" />
    
</LinearLayout>

添加一个按钮用于创建数据库,然后修改MainActivity:

代码语言:javascript复制
package com.example.databasetest

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*

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
        }
    }
}

在onCreate()中创建了一个MyDatabaseHelper对象,并通过构造函数的参数将数据库名指定为BookStore.db,版本号为1。然后再按钮点击事件中注册getWritableDatabase()方法创建数据库。

升级数据库

添加一张Category表 MyDatabaseHelper:

代码语言:javascript复制
package com.example.databasetest

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.widget.Toast

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)"

    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, "Create succeeded", Toast.LENGTH_SHORT).show()
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {

    }
}

如果建表不成功可以把原来的程序卸载因为之前的操作已经存在一个表。 还有一种方法: 修改MyDatabaseHelper:

代码语言:javascript复制
package com.example.databasetest

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.widget.Toast

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)"

    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, "Create succeeded", Toast.LENGTH_SHORT).show()
    }

    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)
    }
}

DROP语句:如果发现数据库中已经存在Book表或Category表,就将这两个表删除,然后调用onCreate()重新创建。 让onUpgrade()方法执行: SQLiteOpenHeloer的第四个参数版本号,当时传入的1,只要传入比1大的数就可以让onUpgrade执行。 修改MainActivity:

代码语言:javascript复制
package com.example.databasetest

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*

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
        }
    }
}

重新运行程序点击按钮会出现创建成功的提示。

添加数据

CDUR 添加数据:insert 查询数据:select 更新数据:update 删除数据:delete 调用SQLiteOpenHelper的getReadableDatabase()或getWritableDatabase()方法可以用于创建和升级数据库并返回一个SQLiteDatabase对象,借助这个对象可以对数据就行CRUD操作。

insert()方法: 三个参数:第一个表名,向哪个表添加数据;第二个用于未指定添加数据的情况下给某些可为空的列自动赋值NULL,传入null即可;第三个是一个ContentValues对象,它提供一系列的put()方法重载,用于向ContentCalues中添加数据,只需要将表中的每个列名以及相应的代添加数据传入即可。

修改activity_main.xml:

代码语言:javascript复制
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <Button
        android:id="@ id/createDatabase"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Create Database" />

    <Button
        android:id="@ id/addData"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Add Data" />
    
</LinearLayout>

添加一个添加数据的按钮。 修改MainActivity:

代码语言:javascript复制
package com.example.databasetest

import android.content.ContentValues
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*

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
        }
        addData.setOnClickListener { 
            val db = dbHelper.writableDatabase
            val values1 = ContentValues().apply { 
                put("name", "The Da Vinci Code")
                put("author", "Dan Brown")
                put("pages", 454)
                put("price", 16.96)
            }
            db.insert("Book", null, values1)
            val values2 = ContentValues().apply { 
                put("name", "The Lost Symbol")
                put("author", "Dan Brown")
                put("pages", 510)
                put("price", 19.95)
            }
            db.insert("Book", null, values2)
        }
    }
}

更新数据

update()方法: 四个参数:第一个表名;第二个ContentValues对象,要把更新数据在这里组装进去;第三、四参数用于约束更新某一行或某几行中的数据,不指定的话默认会更新所有行

降低第一本书的价格: 修改activity_main.xml:

代码语言:javascript复制
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <Button
        android:id="@ id/createDatabase"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Create Database" />

    <Button
        android:id="@ id/addData"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Add Data" />
    
    <Button
        android:id="@ id/updateData"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Update Data" />

</LinearLayout>

添加按钮

修改MainActivity:

代码语言:javascript复制
package com.example.databasetest

import android.content.ContentValues
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*

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
        }
        addData.setOnClickListener {
            val db = dbHelper.writableDatabase
            val values1 = ContentValues().apply {
                put("name", "The Da Vinci Code")
                put("author", "Dan Brown")
                put("pages", 454)
                put("price", 16.96)
            }
            db.insert("Book", null, values1)
            val values2 = ContentValues().apply {
                put("name", "The Lost Symbol")
                put("author", "Dan Brown")
                put("pages", 510)
                put("price", 19.95)
            }
            db.insert("Book", null, values2)
        }
        updateData.setOnClickListener { 
            val db = dbHelper.writableDatabase
            val values = ContentValues()
            values.put("price", 10.99)
            db.update("Book", values, "name = ?", arrayOf("The Da Vinci Code"))
        }
    }
}

db.update("Book", values, "name = ?", arrayOf("The Da Vinci Code")) 第三个参数对应的是SQL语句的where部分,表示更新所有name等于?的行,而?是一个占位符,可以通过第四和参数提供的一个字符串数组为第三个参数中的每个占位符指定相应的内容,arrayOf()方法是Kotlin中提供的一种用于便捷创建数组的内置方法。

删除数据

delete()方法: 三个参数:第一个表名;第二、三用于约束删除某一行或某几行数据,不指定的话默认删除所有行。

修改activity_main,添加一个按钮名为deleteData.

修改ActivityMain:

代码语言:javascript复制
package com.example.databasetest

import android.content.ContentValues
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*

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
        }
        addData.setOnClickListener {
            val db = dbHelper.writableDatabase
            val values1 = ContentValues().apply {
                put("name", "The Da Vinci Code")
                put("author", "Dan Brown")
                put("pages", 454)
                put("price", 16.96)
            }
            db.insert("Book", null, values1)
            val values2 = ContentValues().apply {
                put("name", "The Lost Symbol")
                put("author", "Dan Brown")
                put("pages", 510)
                put("price", 19.95)
            }
            db.insert("Book", null, values2)
        }
        updateData.setOnClickListener {
            val db = dbHelper.writableDatabase
            val values = ContentValues()
            values.put("price", 10.99)
            db.update("Book", values, "name = ?", arrayOf("The Da Vinci Code"))
        }
        deleteData.setOnClickListener { 
            val db = dbHelper.writableDatabase
            db.delete("Book", "pages > ?", arrayOf("500"))
        }
    }
}

通过第二、三个参数指定页数大于500的书

查询数据

query()方法: 七个参数:第一个表名;第二个指定去查询哪几列,不指定默认查询所有列;第三、四个用于约束查询某一行或某几行的数据,不指定默认查询所有行的数据;第五个指定需要去group by的列,不指定则表示不对查询结果进行group by操作;第六个用于对group by之后的数据进行进一步的过滤,不指定则表示不进行过滤;第七个用于指定查询结果的排序方式,不指定则使用默认的排序方式。

query()方法参数

对应SQL部分

描述

table

from table_name

指定查询的表名

columns

select column1, column2

指定查询的列名

selection

where column = value

指定where的约束条件

selectionArgs

-

为where中的占位符提供具体的值

groupBy

group by column

指定需要group by的列

having

having column = value

对group by的列

orderBy

order by column1, column2

指定查询结果的排序方式

调用query()方法后返回一个Cursor对象,查询到的所有数据都将从这个对象中取出。

修改activity_main,添加一个名为queryData的按钮

修改MianActivity:

代码语言:javascript复制
package com.example.databasetest

import android.content.ContentValues
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*

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
        }
        addData.setOnClickListener {
            val db = dbHelper.writableDatabase
            val values1 = ContentValues().apply {
                put("name", "The Da Vinci Code")
                put("author", "Dan Brown")
                put("pages", 454)
                put("price", 16.96)
            }
            db.insert("Book", null, values1)
            val values2 = ContentValues().apply {
                put("name", "The Lost Symbol")
                put("author", "Dan Brown")
                put("pages", 510)
                put("price", 19.95)
            }
            db.insert("Book", null, values2)
        }
        updateData.setOnClickListener {
            val db = dbHelper.writableDatabase
            val values = ContentValues()
            values.put("price", 10.99)
            db.update("Book", values, "name = ?", arrayOf("The Da Vinci Code"))
        }
        deleteData.setOnClickListener {
            val db = dbHelper.writableDatabase
            db.delete("Book", "pages > ?", arrayOf("500"))
        }
        queryData.setOnClickListener { 
            val db = dbHelper.writableDatabase
            val cursor = db.query("Book", null, null, null, null, null, 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"))
                    Log.d("MainActivity", "name is $name")
                    Log.d("MainActivity", "author is $author")
                    Log.d("MainActivity", "pages is $pages")
                    Log.d("MainActivity", "price is $price")
                } while (cursor.moveToNext())
            }
            cursor.close()
        }
    }
}

调用Cursor对象的moveToFirst()方法将数据指针移动到第一行位置。 getColumnIndex()方法获取某一列在表中对应的位置索引,然后将这个索引传入相应的取值方法中,就可以读取数据了。 最后记得关闭。

使用SQL操作数据库

添加数据:

代码语言:javascript复制
db.execSQL("insert into Book (name, author, pages, price) values(?, ?, ?, ?)"), arrayOf("The Da Vinci Code", "Dan Brown", "454", "16.96")

更新数据:

代码语言:javascript复制
db.execSQL("update Book set price = ? where name = ?", arrayOf("10.99", "The Da Vinci Code"))

删除数据:

代码语言:javascript复制
db.execSQL("delete from Book where pages > ?", arrayOf("500"))

查询数据:

代码语言:javascript复制
val cursor = db.rawQuery("select * from Book", null)

SQLite实践

使用事务

让一系列操作要么全部完成,要么一个也不完成。 将DatabaseTest项目中Book表的数据全部废弃,然后添加。删除旧数据和添加新数据的操作必须一起完成,否则就要继续保留原来的旧数据。 修改activity_main:

代码语言:javascript复制
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <Button
        android:id="@ id/createDatabase"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Create Database" />

    <Button
        android:id="@ id/addData"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Add Data" />

    <Button
        android:id="@ id/updateData"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Update Data" />

    <Button
        android:id="@ id/deleteData"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Delete Data" />

    <Button
        android:id="@ id/queryData"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Query Data" />
    
    <Button
        android:id="@ id/replaceData"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Replace Data" />

</LinearLayout>

添加了一个replaceData按钮用于进行替换操作。 修改MainActivity:

代码语言:javascript复制
package com.example.databasetest

import android.content.ContentValues
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*
import java.lang.Exception
import java.lang.NullPointerException

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
        }
        addData.setOnClickListener {
            val db = dbHelper.writableDatabase
            val values1 = ContentValues().apply {
                put("name", "The Da Vinci Code")
                put("author", "Dan Brown")
                put("pages", 454)
                put("price", 16.96)
            }
            db.insert("Book", null, values1)
            val values2 = ContentValues().apply {
                put("name", "The Lost Symbol")
                put("author", "Dan Brown")
                put("pages", 510)
                put("price", 19.95)
            }
            db.insert("Book", null, values2)
        }
        updateData.setOnClickListener {
            val db = dbHelper.writableDatabase
            val values = ContentValues()
            values.put("price", 10.99)
            db.update("Book", values, "name = ?", arrayOf("The Da Vinci Code"))
        }
        deleteData.setOnClickListener {
            val db = dbHelper.writableDatabase
            db.delete("Book", "pages > ?", arrayOf("500"))
        }
        queryData.setOnClickListener {
            val db = dbHelper.writableDatabase
            val cursor = db.query("Book", null, null, null, null, null, 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"))
                    Log.d("MainActivity", "name is $name")
                    Log.d("MainActivity", "author is $author")
                    Log.d("MainActivity", "pages is $pages")
                    Log.d("MainActivity", "price is $price")
                } while (cursor.moveToNext())
            }
            cursor.close()
        }
        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() // 结束事务
            }
        }
    }
}

首先调用beginTransaction()方法开启一个事务,完成删除和添加后调用setTransactionSuccessful()表示事务已经执行成功,最后再finally中调用endTransaction()结束事务。

升级数据库的最佳写法

之前升级数据库是简单的在onUpgrade()方法中删除当前所有表然后重新执行一遍onCreate()。 这样做的弊端为如果你的应用升级一次数据库用户之前的数据就会被清空。

当指定的数据库版本号大于当前数据库版本号的时候,就会进入onUpgrade()方法中执行更新操作,这里需要为每一个版本号赋予其所对应的数据库变动,然后再onUpgrade()方法中对当前数据库的版本号就行判断,在执行相应的改变即可。

例子: MyDatabaseHeloer第1版只需要创建一个Book表:

代码语言:javascript复制
package com.example.databasetest

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.widget.Toast

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)"

    override fun onCreate(db: SQLiteDatabase?) {
        db?.execSQL(createBook)
        Toast.makeText(context, "Create succeeded", Toast.LENGTH_SHORT).show()
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {

    }
}

之后需要向数据库中添加一张Category表。修改MyDatabaseHelper:

代码语言:javascript复制
package com.example.databasetest

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.widget.Toast

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)"

    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, "Create succeeded", Toast.LENGTH_SHORT).show()
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
        if (oldVersion <= 1) {
            db?.execSQL(createCategory)
        }
    }
}

onCreare()方法中新增了一条建表语句,然后又在onUpgrade()方法中添加了一个判断,如果用户的数据库版本号小于等于1,就会创建一张Category。 这样当用户直接安装第2班程序时,就会进入onCreate()方法,将两张表一起创建,而当用户使用第2班的程序覆盖第1版的程序时,就会进入升级数据库的操作,由于Book已经存在,就会只创建个Category。

之后需要在Book表中添加一个category_id字段,修改MyDatabaseHelper:

代码语言:javascript复制
package com.example.databasetest

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.widget.Toast

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,"   
            "category_id integer)"

    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, "Create succeeded", Toast.LENGTH_SHORT).show()
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
        if (oldVersion <= 1) {
            db?.execSQL(createCategory)
        }
        if (oldVersion <= 2) {
            db?.execSQL("alter table Book add column category_id integer")
        }
    }
}

首先在Book中添加了一个category_id列,当用户直接安装第3版时这个新增的列就已经自动添加成功。 老用户升级时如果当前数据库版本号为2就会执行alter命令,为Book表新增一个category_id列。

0 人点赞