Android基础知识 - 内置SQLite数据库

文章目录

  • SQLite数据库简单介绍
  • 创建数据库
    • SQLiteOpenHelper类
      • 简单概述
      • DatabaseTest项目
  • 升级数据库
  • 对表中的数据进行操作
    • 添加数据
    • 更新数据
    • 删除数据
    • 查询数据
  • 使用SQL操作数据库

SQLite数据库简单介绍

  • SQLite是一款轻量级的关系型数据库,它的运算速度非常快,占用资源很少,通常只需要几百K的内存就足够了,因而特别适合在移动设备上使用。
  • SQLite不仅支持标准的SQL语法,还遵循了数据库的ACID事务。
  • 它甚至不用设置用户名和密码就能使用,可以快速上手。
  • 前面所学的文件存储和SharedPreferences存储毕竟只能适用于去保存一些简单的数据和键值对,当需要存储大量复杂的关系型数据的时候,就需要使用SQLite数据库,用来存储这些数据量大、结构性复杂的数据。

创建数据库

SQLiteOpenHelper类

简单概述

  • SQLiteOpenHelper类可以非常简单地对数据库进行创建和升级。
  • SQLiteOpenHelper类是一个抽象类,如果需要使用它,需要创建一个类去实现(继承)它。
  • SQLiteOpenHelper类中有两个抽象方法,分别是
    • onCreate()方法
    • onUpgrade() 方法
    • 我们必须在自己创建的类中去重写这两个方法,然后分别在这两个方法中去实现创建、升级数据库的逻辑。
  • SQLiteOpenHelper 类还有两个非常重要的实例方法
    • getReadableDatabase()方法
    • getWritableDatabase()方法
    • 这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否则创建一个新的数据库),并返回一个可对数据库进行读写操作的对象。不同的是,当数据库不可写入的时候(如磁盘空间已满)getReadableDatabase()方法返回的对象将以只读的方式打开数据库,而getWritableDatabase()方法则将出现异常。
  • SQLiteOpenHelper 类中有两个构造方法可供重写,一般使用参数少一点的那个构造方法即可。
    • 第一参数是Context,这个没什么好说的,必须要有它才能对数据库进行操作。
    • 第二个参数是数据库名,创建数据库时使用的就是这里指定的名称。
    • 第三个参数允许我们在查询数据的时候返回一个自定义的Cursor,一般都是传入null。
    • 第四个参数表示我们当前数据库的版本号,可用于对数据库进行升级操作。
  • 构建出SQLiteOpenHelper 的实例之后,在调用它的getReadableDatabase()或getWritableDatabase()方法就能够创建数据库了,数据库文件的存放目录,可以看我上篇博文的介绍 Android Studio中查看SQlite数据库和表的创建情况 。此时,重写的onCreate()方法也会得到执行,所以通常这里会去处理一些创建表的逻辑。

DatabaseTest项目

  • 创建一个名为BookStore.db的数据库,然后在这个数据库中新建一张Book表,表中有id(主键)、作者、价格、页数和书名等列。创建数据库表当然还是需要用建表语句的,Book表的建表语句如下所示:
    private static final String CREATE_BOOK = "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类继承自SQLiteOpenHelpler
package com.example.myapplication;

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

import androidx.annotation.Nullable;

public class MyDatabaseHelper extends SQLiteOpenHelper {

    private Context mContext;
    private static final String CREATE_BOOK = "create table Book ("
                    + "id integer primary key autoincrement, "
                    + "author text, "
                    + "price real, "
                    + "pages integer, "
                    + "name text)";


    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_LONG).show();
    }

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

    }
}
/* 可以看到我们把建表语句改成了一个字符串常量,然后在onCreate()方法中又调
用了SQLiteDatabase的execSQL()方法区执行这条语句,并弹出一个Toast提示创建
成功,这样就可以保证在数据库创建完成的同时还能成功创建Book表。*/
  • 修改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中的代码,如下所示:
package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbOpenHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbOpenHelper = new MyDatabaseHelper(this,"BookStore.db",null,1);
        Button createDatabase = (Button)findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dbOpenHelper.getWritableDatabase();
            }
        });
   }
}
/* 这里我们在onCreate()方法中构建了一个MyDatabaseHelper对象,并且通过构造函数的参数
将数据库名改为BookStore.db,版本号指定为1,然后在Create Database按钮的点击事件里调用了
getWritableDatabase()方法。这样当第一次点击Create Database按钮时,就会检测到当前程序中
并没有BookStore.db这个数据库,于是会创建该数据库并调用MyDatabaseHelper中的onCreate()
方法,这样Book表就会得到创建,然后会弹出一个Toast提示创建成功。再次点击Create Database
按钮时,会发现此时已经存在BookStore.db数据库了,因此不会再创建一次。*/
  • 运行一次代码,在程序主界面上点击Create Database按钮,结果如图所示。
    Android基础知识 - 内置SQLite数据库_第1张图片
  • 此时BookStore.db数据库和Book表都已经创建成功了,为证实它们存在,我们需要使用上篇博文 Android Studio中查看SQlite数据库和表的创建情况里提到的方法进行检验。
    Android基础知识 - 内置SQLite数据库_第2张图片

升级数据库

  • onUpgrade()方法是用于对数据库进行升级的,它在整个数据库的管理当中起着非常重要的作用。
  • 目前数据库中已经有一张Book表存放书籍的各种详细信息,如果我们想再添加一张Category表用于记录书籍的分类该怎么做呢?
  • 比如Category表中有id(主键)、分类名和分类代码这几个列。
  • 将建表语句添加到MyDatabaseHelper类中,代码如下:
public class MyDatabaseHelper extends SQLiteOpenHelper {

    private Context mContext;
    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)";

    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_LONG).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        
    }
}
/*
	运行上面的程序,并点击Create Database按钮,发现竟然没有弹出创建成功的提示。
	当然,通过adb工具到数据库中再去检查下,这样你会更加确认,Category表没有创建成功。
	思考没有创建成功的原因,因为此时的BookStore.db数据库已经存在了,之后不管我们怎样
	点击Create Database按钮,MyDatabaseHelper中的onCreate()方法都不会再执行,因此
	新添加的表也就无法得到创建了。
	
*/
  • 解决上面的问题很简单,只需要先将程序卸载掉,对应的就是 清除模拟器中的数据(Wipe Data),然后重新运行,这时BookStore.db数据库就已经不存在了,如果再点击Create Database按钮,MyDatabaseHelper中的onCreate()方法就会执行,这时Category表就可以创建成功了。
  • 不过通过卸载数据库的方法来新增一张表毫无疑问是很极端的方法,其实我们只需要巧妙地运用SQLiteOpenHelper的升级功能就可以很轻松地解决这个问题。修改MyDatabaseHelper中的代码,如下所示:
    
public class MyDatabaseHelper extends SQLiteOpenHelper{
	@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 dbOpenHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbOpenHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);
        Button createDatabase = (Button)findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dbOpenHelper.getWritableDatabase();
            }
        });
   }
}
/*
这里将数据库的版本号改为2,表示我们对数据库进行升级了。现在重新运行程序,并点击
Create Database按钮,这时会再次弹出创建成功的提示。为了验证一下Category表
是不是已经创建成功了,我们可以利用adb工具打开数据库检验。
*/

在这里插入图片描述

对表中的数据进行操作

  • 对数据进行的操作无非四种,即CRUD。其中C代表添加,Create;R代表查询,Retrieve;U代表更新,Update;D代表删除,Delete。每一种操作又各自对应了一种SQL命令,添加数据时使用insert,查询数据时使用select,更新数据时使用update,删除数据时使用delete。但是除了SQL命令之外,Android还提供了一套辅助性方法。
  • 调用SQLiteOpenHelper的getReadableDatabase()或getWritableDatabase()方法是可以用于创建和升级数据库的,不仅如此,这两个方法都会返回一个SQLiteDatabse对象,借助这个对象我们就可以对数据进行CRUD操作了。

添加数据

  • SQLiteDatabase中提供了一个insert()方法,这个方法就是专门用来添加数据的。
    • 它接收三个参数,第一个参数是表名,我们希望向哪张表里添加数据,这里就传入该表的名字。
    • 第二个参数用于在未指定添加数据的情况下给某些可为空的列自动赋值NULL,一般我们用不到这个功能,直接传入null即可。
    • 第三个参数是一个ContentValues对象,它提供了一系列的put()方法重载,用于向ContentValues中添加数据,只需要将表中的每个列名以及相应的待添加数据传入即可。
  • 举例说明,修改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:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/add_data"
        android:text="Add Data"
        />
LinearLayout>

  • 修改MainActivity中的代码,如下所示。
public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbOpenHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbOpenHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);
        ......
        Button addData = (Button) findViewById(R.id.add_data);
        addData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                values.put("author","Dan Brown");
                values.put("price",19.6);
                values.put("pages",454);
                values.put("name","The Da Vinci Code");
                db.insert("Book",null,values);// 插入第一条数据
                values.put("author","Dan Brown");
                values.put("price",19.95);
                values.put("pages",550);
                values.put("name","The Lost Symbol");
                db.insert("Book",null,values);// 插入第二条数据

            }
        });
    }
}
/*
在添加数据的按钮点击事件里,我们先获取到了SQLiteDatabase 对象,
然后使用ContentValues来对要添加的数据进行组装。我们发现没有对
id那一列进行赋值,这是因为在前面创建表的时候我们就将id设置为自增长
了,它的值会在入库的时候自动生成,所以不需要手动给它赋值,接下来调用
insert()方法将数据添加到表当中,注意这里我们实际添加了两条数据,上述代码
中使用了ContentValues分别组装了两次不同的内容,并调用了两次insert()方法。
*/
  • 接下来运行程序,界面和adb工具查询结果如下:
    • 界面
      Android基础知识 - 内置SQLite数据库_第3张图片
    • adb查询结果
      在这里插入图片描述

更新数据

  • SQLiteDatabase提供了一个update()方法用于对数据进行更新
    • 第一个参数,表名,在这里指定去更新哪张表里的数据
    • 第二个参数,ContentValues对象,要把更新的数据在这里组装进去。
    • 第三、四个参数,用于去约束更新某一行或某几行中的数据,不指定的话默认就是更新所有的行。
  • 在以上数据库和表中进行修改:将添加进数据库里的第一本书的价格降低,来吸引更多的顾客。
  • 修改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:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/update_data"
        android:text="Update Data"
        />
LinearLayout>
  • 修改MainActivity中的代码,如下所示。
public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbOpenHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbOpenHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);
        ......
        Button updateData = (Button)findViewById(R.id.update_data);
        updateData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                values.put("price",10.99);
                db.update("Book",values,"name = ?", new String[] {"The Da Vinci Code"});
            }
        });
    }
}
/*
这里在更新数据按钮的点击事件里面构建了一个ContentValues对象,并且只给定它指定了一组数据,
说明我们只是想把价格这一列的数据更新成10.99。然后调用了SQLiteDatabase的update()方法去
执行具体的更新操作,可以看到,这里使用了第三、四个参数来指定具体更新哪几行。第三个参数
对应的是SQL语句的where部分,表示去更新所有name等于?的行,而?是一个占位符,可以通过
第四个参数提供的一个字符串数组为第三个参数中的每个占位符指定相应的内容。因此上述代码
想表达的意图就是,将名字是The Da Vinci Code的这本书的价格改为10.99。
*/
  • 重新运行程序,界面如下所示。
    Android基础知识 - 内置SQLite数据库_第4张图片
  • 点击Update Data按钮,再次在adb查询工具查询表中的数据情况,如下所示。
    在这里插入图片描述

删除数据

  • SQLiteDatabase中提供了一个delete()方法专门用于删除数据
    • 第一个参数,表名
    • 第二、三个参数,用于去约束删除某一行或某几行的数据,不指定的话默认就是删除所有行。
  • 修改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:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/delete_data"
        android:text="Delete Data"
        />
LinearLayout>
  • 修改MainActivity中的代码,如下所示。
public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbOpenHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbOpenHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);
        ......
        Button deleteData = (Button)findViewById(R.id.delete_data);
        deleteData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
                db.delete("Book","pages > ?", new String[] {"500"});
            }
        });
    }
}
/*
可以看到我们在删除按钮的点击事件里指明去删除Book表中的数据,并且通过
第二、三参数来指定仅删除那些页数超过500页的书籍。
*/
  • 界面如下所示。
    Android基础知识 - 内置SQLite数据库_第5张图片
  • adb查询工具查询结果如下所示。
    在这里插入图片描述

查询数据

  • SQLiteDatabase中提供了一个query()方法用于对数据进行查询,这里介绍最少参数(7个参数)的方法重载。调用query()方法后会返回一个Cursor对象,各参数含义如下表所示。
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 指定查询结果的排序方式
  • 第二个参数,如果不指定默认查询所有列。
  • 第三、四个参数,不指定则默认是查询所有行的数据。
  • 第五个参数,不指定则表示不对查询结果进行group by的操作。
  • 第六个参数,不指定则表示不进行约束。
  • 第七个参数,不指定则表示使用默认的排序方式。
  • 其他几个query()方法的重载其实也大同小异。
  • 修改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:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/query_data"
        android:text="Query Data"
        />

LinearLayout>
  • 修改MainActivity中的代码,如下所示。
package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbOpenHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbOpenHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);
        ......
        Button queryData = (Button)findViewById(R.id.query_data);
        queryData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
                // 查询表中所有的数据
                Cursor cursor = db.query("Book",null,null,null,null,null,null);
                if(cursor.moveToFirst()){
                    do{
                        // 遍历Cursor对象,取出数据并打印出来
                        @SuppressLint("Range") String author = cursor.getString(cursor.getColumnIndex("author"));
                        @SuppressLint("Range") double price = cursor.getDouble(cursor.getColumnIndex("price"));
                        @SuppressLint("Range") int pages = cursor.getInt(cursor.getColumnIndex("pages"));
                        @SuppressLint("Range") String name = cursor.getString(cursor.getColumnIndex("name"));

                        Log.d("MainActivity",author);
                        Log.d("MainActivity",""+price);
                        Log.d("MainActivity","" + pages);
                        Log.d("MainActivity",name);

                    }while(cursor.moveToNext());
                }
                cursor.close();
            }
        });
    }
}
/*
	可以看到,我们在查询按钮的点击事件里调用了SQLiteDatabase的query()方法
	去查询数据。这里的query()方法非常简单,只是使用了第一个参数指明去查询
	Book表,后面的参数全部为null。这就表示希望查询这张表中的所有数据,虽然
	这张表中目前只剩下一条数据了。查询完之后就得到了一个Cursor对象,接着
	我们调用它的moveToFirst()方法将数据的指针移动到第一行的位置,然后进入
	了一个循环当中,去遍历查询到的每一行数据。在这个循环中可以通过Cursor的
	getColumnIndex()方法获取到某一列在表中对应的位置索引,然后将这个索引
	传入到相应的取值方法中,就可以得到从数据库中读取到的数据了。接着我们用
	Log的方式将取出的数据打印出来,借此来检查一下读取工作有没有成功完成。
	最后调用close()方法来关闭Cursor。
*/
  • 界面如下所示。
    Android基础知识 - 内置SQLite数据库_第6张图片
  • 点击一下Query Data按钮,查看LogCat的打印内容,结果如下所示。
    在这里插入图片描述

使用SQL操作数据库

  • 直接使用SQL来完成前面学过的CRUD(C代表添加,Create;R代表查询,Retrieve;U代表更新,Update;D代表删除,Delete)
//添加数据的方法如下:
db.execSQL("insert into Book (name, author, pages, price) values(?, ?, ?, ?)", new String[]{"The Da Vinci Code", "Dan Brown", "454", "16.96"});
db.execSQL("insert into Book (name, author, pages, price) values(?, ?, ?, ?)", new String[]{"The Lost Symbol", "Dan Brown", "510", "19.95"});
//更新数据的方法如下:
db.execSQL("update Book set price = ? where name = ?", new String[] {"10.99", "The Da Vinci Code"});
//删除数据的方法如下:
db.execSQL("delete from Book where pages > ?", new String[] {"500"});
//查询数据的方法如下
db.execSQL("select * from Book",null);

你可能感兴趣的:(Android开发,sqlite,数据库,android)