【SQLite数据库存储】创建、升级数据库

SQLite数据库存储

SQLite是一款轻量级的关系型数据库,它的运算速度非常快, 占用资源很少,通常只需要几百 K的内存就足够了,因而特别适合在移动设备上使用
SQLite 不仅支持标准的 SQL语法,还遵循了数据库的 ACID 事务,所以只要你以前使用过其他的 关系型数据库,就可以很快地上手 SQLite
SQLite又比一般的数据库要简单得多,它甚 至不用设置用户名和密码就可以使用
Android 正是把这个功能极为强大的数据库嵌入到了 系统当中,使得本地持久化的功能有了一次质的飞跃

前面我们所学的文件存储和 SharedPreferences 存储毕竟只适用于去保存一些简单的数据 和键值对,当需要存储大量复杂的关系型数据的时候,你就会发现以上两种存储方式很难应 付得了

比如我们手机的短信程序中可能会有很多个会话,每个会话中又包含了很多条信息 内容,并且大部分会话还可能各自对应了电话簿中的某个联系人。很难想象如何用文件或者 SharedPreferences来存储这些数据量大、结构性复杂的数据吧?但是使用数据库就可以做得 到

创建数据库

Android为了让我们能够更加方便地管理数据库,专门提供了一个 SQLiteOpenHelper帮助类
首先你要知道 SQLiteOpenHelper是一个抽象类,这意味着如果我们想要使用它的话, 就需要创建一个自己的帮助类去继承它

SQLiteOpenHelper 中有两个抽象方法,分别是 onCreate()onUpgrade(),我们必须在自己的帮助类里面重写这两个方法,然后分别在这两 个方法中去实现创建、升级数据库的逻辑

SQLiteOpenHelper 中还有两个非常重要的实例方法 , getReadableDatabase()getWritableDatabase()。这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否则创建一个新的数据库),并返回一个可对数据库进行读写操作的对象。不 同的是,当数据库不可写入的时候(如磁盘空间已满)getReadableDatabase()方法返回的对象将以只读的方式去打开数据库,而 getWritableDatabase()方法则将出现异常

SQLiteOpenHelper中有两个构造方法可供重写,一般使用参数少一点的那个构造方法即可。这个构造方法中接收四个参数,第一个参数是 Context。第二个参数是数据库名,创建数据库时使用的就是这里指定的名称。第三个参数允许我们在查询数据的时候返回一个自定义的 Cursor,一般都是传入 null。 第四个参数表示当前数据库的版本号,可用于对数据库进行升级操作

构建出 SQLiteOpenHelper 的实例之后,再调用它的 getReadableDatabase()getWritableDatabase()方法就能够创建数据库了,数据库文件会存放在/data/data/包名/databases/目录下。 此时,重写的 onCreate()方法也会得到执行,所以通常会在这里去处理一些创建表的逻辑

栗子
这里我们希望创建一个名为 BookStore.db的数据库,然后在这个数据库中新建一张Book 表,表中有 id(主键)、作者、价格、页数和书名等列

创建数据库表当然还是需要用建表 语句的,Book表的建表语句如下所示

create table Book 
( id integer primary key autoincrement, 
author text, 
price real,
pages integer,
name text)

SQLite的数据类型很简单,integer表示整型,real表示浮点型,text表示文本类型,blob`表示二进制类型

上述建表语句中我们还 使用了 primary keyid列设为主键,并用 autoincrement关键字表示id列是自增长的

新建 MyDatabaseHelper 类继承自 SQLiteOpenHelper

class MyDatabaseHelper extends SQLiteOpenHelper {
    private static final String CREATE_BOOK = "create table book (id integer primary key autoincrement,author text,price real,pages integer,name text)";

    private Context mContext;

    public MyDatabaseHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
        Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

activity_main.xml

<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/create_database"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Create database" />
</LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper myDatabaseHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myDatabaseHelper = new MyDatabaseHelper(this,"BookStore.db",null,1);
        Button create_database = findViewById(R.id.create_database);
        create_database.setOnClickListener(v -> {
            myDatabaseHelper.getWritableDatabase();
        });
    }
}

onCreate()方法中构建了一个 MyDatabaseHelper 对象,并且通过构造函数的 参数将数据库名指定为 BookStore.db,版本号指定为 1
然后在 Create database按钮的点击 事件里调用了getWritableDatabase()方法
这样当第一次点击 Createdatabase 按钮时,就会检测 到当前程序中并没有BookStore.db这个数据库,于是会创建该数据库并调用MyDatabaseHelper中的 onCreate()方法,这样 Book表也就得到了创建,然后会弹出一个 Toast提示创建成功

再次点击 Createdatabase按钮时,会发现此时已经存在 BookStore.db数据库了,因此不会再 创建一次

此时 BookStore.db数据库和 Book表应该都已经创建成功了,因为当你再次点击 Create database按钮时不会再有 Toast弹出。在 /data/data/packagename/databases 下多了 BookStore.db,还有一个 BookStore.db-journal 文件,这是一个为了让数据库能够支持事务而产生的临时日志文件,通常情况下这个文件大小是 0 字节
在这里插入图片描述

下面使用 Kotlin 完成

新建 MyDatabaseHelper

class MyDatabaseHelper extends SQLiteOpenHelper {
    private static final String CREATE_BOOK = "create table book (id integer primary key autoincrement,author text,price real,pages integer,name text)";

    private Context mContext;

    public MyDatabaseHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
        Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

MainActivity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val helper = MyDatabaseHelper(this, "BookStore.db", 1)
        create_database.setOnClickListener {
            helper.writableDatabase
        }
    }
}

使用 Database Navigator 查看

把 BookStore.db 右键 Save as 保存到本机

安装插件 Database Navigator,重启 AS 后,侧边栏会多出 DB Browser
在这里插入图片描述
打开的页面中选中 刚才的 BookStore.db
在这里插入图片描述
确定之后,可以看到确实有一个 Book 表,我们创建成功了
在这里插入图片描述

升级数据库

如果我们想 再添加一张 Category 表用于记录书籍的分类该怎么做呢? 比如 Category 表中有 id(主键)、分类名和分类代码这几个列,那么建表语句就可以 写成

create table Category ( id integer primary key autoincrement, category_name text, category_code integer) 

如果单纯的把这个语句像创建 Book 表一样,加入到 MyDatabaseHelper 中执行,是不能成功创建表的,因为此时 BookStore.db 数据库已经存在了,之后不 管我们怎样点击 Create database 按钮,MyDatabaseHelper 中的 onCreate() 方法都不会再次执 行,因此新添加的表也就无法得到创建了。 解决这个问题的办法也相当简单,只需要先将程序卸载掉,然后重新运行,这时 BookStore.db 数据库已经不存在了,如果再点击 Create database 按钮,MyDatabaseHelper 中 的 onCreate()方法就会执行,这时 Category表就可以创建成功了

不过通过卸载程序的方式来新增一张表是很极端的做法,其实我们只需要运用 MyDatabaseHelper 的升级功能,就可以轻松解决这个问题

MyDatabaseHelper

class MyDatabaseHelper extends SQLiteOpenHelper {
    private static final String CREATE_BOOK = "create table book (id integer primary key autoincrement,author text,price real,pages integer,name text)";
    private static final String CREATE_CATEGORY ="create table Category ( id integer primary key autoincrement, category_name text, category_code integer) ";

    private Context mContext;

    public MyDatabaseHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
        db.execSQL(CREATE_CATEGORY);
        Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("drop table if exists Book");
        db.execSQL("drop table if exists Category");
        onCreate(db);
    }
}

我们在 onUpgrade()方法中执行了两条 DROP 语句,如果发现数据库中已经 存在 Book 表或 Category 表,就将这两张表删除掉,然后再调用 onCreate()方法去重新创建。这里先将已经存在的表删除掉,是因为如果在创建表时发现这张表已经存在了,就会直接报错

接下来的问题就是如何让 onUpgrade()方法能够执行了,还记得 SQLiteOpenHelper的构 造方法里接收的第四个参数吗?它表示当前数据库的版本号,之前我们传入的是 1,现在只 要传入一个比 1大的数,就可以让 onUpgrade()方法得到执行了。修改 MainActivity中的代码

public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper myDatabaseHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myDatabaseHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);
                Button create_database = findViewById(R.id.create_database);
        create_database.setOnClickListener(v -> {
            myDatabaseHelper.getWritableDatabase();
        });
    }
}

这里将数据库版本号指定为 2,表示我们对数据库进行升级
现在重新运行程序,并 点击 Createdatabase 按钮,这时就会再次弹出创建成功的提示。为了验证一下 Category表是 不是已经创建成功了,我们重新把 Book.db 导出到计算机,在 DB Browser 中重新导入
在这里插入图片描述
使用Kotlin实现

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 creatCategory = "create table Category ( id integer primary key autoincrement, category_name text, category_code integer) "
    override fun onCreate(db: SQLiteDatabase) {
        db.execSQL(createBook)
        db.execSQL(creatCategory)
        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)
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值