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

SQLite数据库存储

Android系统了数据库
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表示二进制类型

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

新建MyDatabaseHelper 类继承自 SQLiteOpenHelper

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

public 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(Context context, String name, SQLiteDatabase.CursorFactory factory, int version, Context mContext) {
        super(context, name, factory, version);
        this.mContext = mContext;
    }

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

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }
}

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

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

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,"BookStroe.db",null,1);
        Button createDatabase = (Button) findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                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弹出

使用 adbshell来对数据库和表的创建情况进行检查

在环境变量中将platform-tools改为全局变量:

电脑→属性→高级→环境变量,然后在 系统变量里找到 Path并点击编辑,将 platform-tools目录配置进去

打开命令行界面,输入以下命令,就 会进入到设备的控制台

adb shell

然后使用 cd命令进入/data/data/com.example.databasetest/databases/

使用ls命令查看到该目录里的文件

这里写图片描述

这个目录下出现了两个数据库文件,一个正是我们创建的 BookStore.db,而另一个 BookStore.db-journal则是为了让数据库能够支持事务而产生的临时日志文件,通常情况下这 个文件的大小都是 0字节

接下来我们就要借助 sqlite命令来打开数据库了,只需要键入 sqlite3,后面加上数据库 名即可,

# sqlite3 BookStroe.db

这里写图片描述

查看数据库中有哪些表

.table

这里写图片描述

可以看到,此时数据库中有两张表,android_metadata表是每个数据库中都会自动生成的,不用管它,而另外一张 Book表就是我们在 MyDatabaseHelper中创建的了

查看建标语句

.schema

这里写图片描述

之后键入.exit或.quit 命令可以退出数据库的编辑

再键入 exit命令就可以退出设备控制台了

升级数据库

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

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

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

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

MyDatabaseHelper

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

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

    public MyDatabaseHelper(Context context, String name, 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()方法能够执行了,还记得 SQLiteOpenHelper的构 造方法里接收的第四个参数吗?它表示当前数据库的版本号,之前我们传入的是 1,现在只 要传入一个比 1大的数,就可以让 onUpgrade()方法得到执行了。修改 MainActivity中的代码

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

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,"BookStroe.db",null,2);
        Button createDatabase = (Button) findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                myDatabaseHelper.getWritableDatabase();
            }
        });
    }
}

这里将数据库版本号指定为 2,表示我们对数据库进行升级
现在重新运行程序,并 点击 Createdatabase按钮,这时就会再次弹出创建成功的提示。为了验证一下 Category表是 不是已经创建成功了,我们在 adbshell中打开 BookStore.db数据库,然后键入.table命令

这里写图片描述

接着键入.schema命令查看一下建表语句

这里写图片描述

由此可以看出,Category 表已经创建成功了,同时也说明我们的升级功能的确起到了 作用

你可能感兴趣的:(Android从入门到放弃)