1 创建SQLite数据库

 

Android系统推荐的创建SQLite数据库的方法,是创建继承自SQLiteOpenHelper类的子类,并且重写其中的两个抽象方法onCreate()和onUpdate(),然后分别在这两个方法中去实现创建、升级数据库的逻辑。

除了上面提到的两个抽象方法外,SQLiteOpenHelper中还有两个非常重要的实例方法:getReadableDatabase()和getWriteableDatabase(),SQLiteOpenHelper的子类通过这两个方法来获取SQLite数据库的实例对象,并保证以同步方式访问。通常情况下getReadableDatabase()和getWriteableDatabase()方法都是创建或打开一个现有的数据库,并返回一个可对数据库进行读写操作的对象。但在某些情况下,例如磁盘空间已满,getReadableDatabase()方法返回的对象将以只读的方式去打开数据库,而getWriteableDatabase()方法将抛出异常。

SQLiteOpenHelper类常用的方法如下表

public class DBHelper extends SQLiteOpenHelper {

    private static String DB_NAME="contacts.db";//数据库名
    private static int DB_VERSIOIN=1;


    //创建数据库
    public DBHelper(Context context){
        //4个参数:
        //1,上下文;2数据库的名称;3一般都为null,用于创建一个Cursor对象;4版本号。
        super(context,DB_NAME,null,DB_VERSIOIN);
    }

    //用于建表,在数据库第一次创建的时候会调用
    //SQLiteDatabase:就是我们要操纵的数据库对象
    @Override
    public void onCreate(SQLiteDatabase db) {
            String  sql= "CREATE TABLE contace (_id INTEGER PRIMARY KEY AUTOINCREMENT,name VARCHAR(10),phonenumber VARCHAR(12))";
            db.execSQL(sql);//exec:execute:执行
    }

    //当数据库版本号增加时调用
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

只有在真正操作数据库,如调用getReadableDatabase()或者getWriteableDatabase()方法时,数据库才会被创建,创建的数据库文件位于/data/data/<packagename>/database/目录下。

多学一招:升级SQLite数据库。

除了onCreate()方法外,SQLiteOpenHelper中还有一个抽象方法onUpdate(),该方法是用于对数据库进行升级的,它在整个Android应用数据库管理工作中起着非常重要的作用。

往往,随着Android应用程序的版本更新,如果之前的数据库表结构发生了变化或者添加了新表,这时就需要对数据库也进行升级。表5-2中已经介绍过,SQLiteOpenHelper类的构造方法接收的其中一个参数是int类型的version,它的含义就是当前数据库的版本号。下面举例进行说明。假设在Android应用1.0版本中,使用SQLiteOpenHelper访问数据库时,version参数传入的值为1,那么数据库版本号1就会记录在数据库中;当应用程序升级到1.1版本,数据库往往也需要跟着发生变化,这时1.1版本的程序中就要使用一个大于1的整数作为参数version的值来创建SQLiteOpenHelper对象,用于访问新的数据库,例如可以将version参数设置为2。当系统在构造SQLiteOpenHelper类的对象时,如果发现传入的版本号跟之前数据库记录的不一致,就会自动调用onUpgrade()方法,使得开发者可以在此方法里执行数据库的升级操作。

接下来,通过一个实例演示如何实现SQLite数据库的升级。首先,新建一个名为SQLiteUpdate的项目,指定包名为cn.edu.ayit.sqliteupdate,待项目创建成功后,在包上右击,并在弹出的快捷菜单中依次选择New→JavaClass命令

在上述对话框中,在Name文本框中输入DBHelper,Superclass指定为android.database.sqlite.SQLiteOpenHelper,然后单击OK按钮完成创建,接着修改DBHelper的代码,具体如下所示:

package com.example.sqliteupdate;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

import androidx.annotation.Nullable;

public class DBHelper extends SQLiteOpenHelper {

    private static final String TAG="DBHelper";
    private static String DB_Name="student.db";//数据库名
    private static int DB_VERSION = 2;


    public DBHelper(Context context) {
        super(context, DB_Name, null, DB_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.i(TAG ,"数据库创建了...");
        String  sql = "CREATE TABLE student(_id INTEGER PRIMARY KEY AUTOINCREMENT,name VARCHAR(10),age VARCHAR(4),sex VARCHAR(2))";
        db.execSQL(sql);//执行建表的SQL语句
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.i(TAG ,"数据库升级了...");
    }
}

DBHelper用于建库、建表和数据库升级的相关处理,编写完成后,在MainActivity的onCreate()方法里添加两行代码,具体如下所示。

 DBHelper  dbHelper = new DBHelper(this);
        SQLiteDatabase db = dbHelper.getReadableDatabase();

 

2数据库的CRUD

SQLiteDatabase是一个数据库访问类,该类封装了一系列数据库操作的API,可以对数据进行CRUD操作,即数据库的增删改查。

插入数据 

向数据库中插入数据的示例代码如下所示。

//封装了一个插入数据的方法
    //方法需要传入ContentValues对象
    public long insert(ContentValues values){
        //获取可读写的SQliteDatabase对象
        SQLiteDatabase db = helper.getWritableDatabase();
        //插入一条数据到TABLE_NAME表
        long id = db.insert(TABLE_NAME,null,values);
        //关闭数据库
        db.close();
        return id;
    }

通过编写SQL语句的方式,也可以通过调用execSQL()方法向SQLite数据库中插入一条新的数据。具体代码如下:

 //需要传入一条sql 语句
    //String sql="INSERT INTO contact ('name','lisi','phonenumber','13912345678') "
    public  void insert_sql(String sql){
        SQLiteDatabase db = helper.getWritableDatabase();
        db.execSQL(sql);
    }

 SQLiteDatabase中提供的update()方法,用于对数据进行修改,具体代码如下:

   //修改某个联系人的数据
    public int update(ContentValues values,String name){
        SQLiteDatabase db = helper.getWritableDatabase();
        int number = db.update(TABLE_NAME,values,"name=?",new String[]{name});
        db.close();
        return number;
    }

SQL语句更新数据

  //String sql="UPDATE contact SET phonenumber='139456789123'  where name = 'lisi'"
    public void update_sql(String sql){
        SQLiteDatabase db = helper.getWritableDatabase();
        db.execSQL(sql);
    }

 删除数据

    //删除某个联系人的数据
    public int deleteByName(String name){
        SQLiteDatabase db = helper.getWritableDatabase();
        int number = db.delete(TABLE_NAME,"name= ?",new String[]{name});
        db.close();
        return number;
    }

 SQL删除数据

 //String sql="DELETE FROM contact WHERE name='lisi' "
    public void deltebyName_sql(String sql){
        SQLiteDatabase db = helper.getWritableDatabase();
        db.execSQL(sql);
    }

查询数据

SQLiteDatabase中的query()方法用于对数据进行查询。这个方法的参数相对复杂,最短的一个重载方法也需要传入七个参数

  1. table:指定查询的表名,对应SQL语句fromtable_name。
  2. columns:指定查询的字段名,对应SQL语句“select column1,column2”。
  3. selectionArgs:为where中的占位符提供具体的值。
  4. selectionArgs:为where中的占位符提供具体的值。
  5. groupBy:指定需要分组的列,相当于SQL中的group by语句。
  6. having:相当于SQL中的having子句,对group by后的结果进一步约束。
  7. orderBy:指定查询结果的排序方式,对应SQL语句order by column。 
 //查询所有记录,返回Cursor对象。
    public Cursor selectAll(){
        SQLiteDatabase db =helper.getReadableDatabase();
        return db.query(TABLE_NAME,null,null,null,null,null,null);
    }

Query()方法的返回值是一个Cursor对象,相当于结果集ResultSet。实际上,Cursor是一个游标接口,在数据库操作中作为返回值。它提供了遍历查询结果的方法。

Cursor游标常用方法

 SQLiteDatabase 对象的rawQuery查询数据方法

  //查询指定联系人的记录,需要传一个 联系人的名字
    public Cursor selectAll_sql(String name){
        SQLiteDatabase db =helper.getReadableDatabase();
        String sql = "Select * FROM contact WHERE name=?";
        return db.rawQuery(sql,new String[]{name});
    }

execSQL()方法通过执行一条SQL语句来完成增删改的操作,但这个方法没有返回值。而insert()、update()和delete()方法都有返回结果,分别表示新插入的记录对应的行号以及更新和删除操作影响的记录条数。 

3SQLite事务操作

数据库事务(Transaction)是并发控制的基本单位。所谓的事务,指的是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。例如,银行转账操作,从一个账号扣款并使另一个账号增款,只有这两部分都完成才认为转账成功,如果其中一个操作出现异常执行失败,则会导致两个账户的金额不同步。因此,必须做到这两个操作要么都执行,要么都不执行。所以,应该把它们看成一个事务。事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性。

SQLite中当然引入了事务,接下来通过下面的示例代码来模拟银行的转账业务,演示如何执行一个事务操作。

上述代码中,首先得到一个可写的SQLiteDatabase对象,然后使用SQLiteDatabase的beginTransaction()方法去开启一个事务,程序执行到endTransaction()方法时会检查事务的标志是否为成功,如果程序执行到endTransaction()之前调用了setTransactionSuccessful()方法设置事务的标志为成功,则所有从beginTransaction()方法开始的操作都会被提交,如果没有调用setTransactionSuccessful()方法则回滚事务。最后需要关闭事务,如果不关闭事务,则事务只有等到超时才会自动结束,会降低数据库并发执行的效率。 

4我的通讯簿实例

(1)新建一个名为MyContactBook的项目,然后在项目中添加一个DBHelper类用于创建数据库和建立数据库表,具体代码如下所示。

package com.example.mycontackbook;

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

public class DBHelper extends SQLiteOpenHelper {

    private static String DB_NAME="contacts.db";//数据库名
    private static int DB_VERSIOIN=1;


    //创建数据库
    public DBHelper(Context context){
        //4个参数:
        //1,上下文;2数据库的名称;3一般都为null,用于创建一个Cursor对象;4版本号。
        super(context,DB_NAME,null,DB_VERSIOIN);
    }

    //用于建表,在数据库第一次创建的时候会调用
    //SQLiteDatabase:就是我们要操纵的数据库对象
    @Override
    public void onCreate(SQLiteDatabase db) {
            String  sql= "CREATE TABLE contace (_id INTEGER PRIMARY KEY AUTOINCREMENT,name VARCHAR(10),phonenumber VARCHAR(12))";
            db.execSQL(sql);//exec:execute:执行
    }

    //当数据库版本号增加时调用
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

(2)在项目指定的包cn.edu.ayit.mycontactbook下新建一个dao(DataAccessObject,即数据访问对象)包,并在dao包下创建一个ContactDao类,然后把对contact表进行CRUD的操作封装在这个类中。具体代码如下所示。

package com.example.mycontackbook.dao;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.example.mycontackbook.DBHelper;

public class ContactDao {
    private Context mContext;
    private DBHelper helper;
    private static String TABLE_NAME="contact";

    //生成DBHelper类
    public ContactDao(Context context){
        this.mContext =context;
        helper =new DBHelper(mContext);
    }

    //封装了一个插入数据的方法
    //方法需要传入ContentValues对象
    public long insert(ContentValues values){
        //获取可读写的SQliteDatabase对象
        SQLiteDatabase db = helper.getWritableDatabase();
        //插入一条数据到TABLE_NAME表
        long id = db.insert(TABLE_NAME,null,values);
        //关闭数据库
        db.close();
        return id;
    }

    //需要传入一条sql 语句
    //String sql="INSERT INTO contact ('name','lisi','phonenumber','13912345678') "
    public  void insert_sql(String sql){
        SQLiteDatabase db = helper.getWritableDatabase();
        db.execSQL(sql);
    }

    //删除全部数据
    public int deleteAll(){
        SQLiteDatabase db = helper.getWritableDatabase();
        int number = db.delete(TABLE_NAME,null,null);
        db.close();
        return number;
    }


    //删除某个联系人的数据
    public int deleteByName(String name){
        SQLiteDatabase db = helper.getWritableDatabase();
        int number = db.delete(TABLE_NAME,"name= ?",new String[]{name});
        db.close();
        return number;
    }

    //String sql="DELETE FROM contact WHERE name='lisi' "
    public void deltebyName_sql(String sql){
        SQLiteDatabase db = helper.getWritableDatabase();
        db.execSQL(sql);
    }

    //修改某个联系人的数据
    public int update(ContentValues values,String name){
        SQLiteDatabase db = helper.getWritableDatabase();
        int number = db.update(TABLE_NAME,values,"name=?",new String[]{name});
        db.close();
        return number;
    }


    //String sql="UPDATE contact SET phonenumber='139456789123'  where name = 'lisi'"
    public void update_sql(String sql){
        SQLiteDatabase db = helper.getWritableDatabase();
        db.execSQL(sql);
    }

    //查询所有记录,返回Cursor对象。
    public Cursor selectAll(){
        SQLiteDatabase db =helper.getReadableDatabase();
        return db.query(TABLE_NAME,null,null,null,null,null,null);
    }


    //查询指定联系人的记录,需要传一个 联系人的名字
    public Cursor selectAll_sql(String name){
        SQLiteDatabase db =helper.getReadableDatabase();
        String sql = "Select * FROM contact WHERE name=?";
        return db.rawQuery(sql,new String[]{name});
    }
}

(3)修改MainActivity的布局文件,具体代码如下所示。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="8dp">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="我的通讯薄"
        android:textColor="#000000"
        android:textSize="26sp"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="姓        名:"
            android:textColor="#000000"
            android:textSize="20sp"/>
        <EditText
            android:id="@+id/et_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:hint="联系人姓名"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="联系方式:"
            android:textColor="#000000"
            android:textSize="20sp"/>
        <EditText
            android:id="@+id/et_phone_number"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:hint="联系方式"
            android:inputType="number"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_insert"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="添加"/>
        <Button
            android:id="@+id/btn_delete"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="删除"/>

        <Button
            android:id="@+id/btn_update"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="修改"/>
        <Button
            android:id="@+id/btn_query"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="查询"/>
    </LinearLayout>

    <TextView
        android:id="@+id/tv_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp"/>
</LinearLayout>

主界面预览效果

(4)布局文件编写完成后,需要在MainActivity中实现处理逻辑,具体代码如下所示。

package com.example.mycontactbook;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ContentValues;
import android.database.Cursor;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.example.mycontactbook.dao.ContactDao;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private EditText etName;
    private EditText etPhoneNumber;
    private Button btnInsert;
    private Button btnDelete;
    private Button btnUpdate;
    private Button btnQuery;
    private TextView tvList;

    //Data Access Object:对contact表进行CRUD操作的类
    private ContactDao dao;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //初始化控件
        initView();
        dao = new ContactDao(this);
    }

    private void initView(){
        etName= (EditText) findViewById(R.id.et_name);
        etPhoneNumber=(EditText)findViewById(R.id.et_phone_number);

        btnInsert=(Button) findViewById(R.id.btn_insert);
        btnDelete=(Button) findViewById(R.id.btn_delete);
        btnUpdate=(Button) findViewById(R.id.btn_update);
        btnQuery=(Button) findViewById(R.id.btn_query);
        tvList=(TextView)findViewById(R.id.tv_list);

        //为按钮注册监听
        btnInsert.setOnClickListener(this);

        btnDelete.setOnClickListener(this);
        btnUpdate.setOnClickListener(this);
        btnQuery.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        String name=null;
        String phoneNum=null;
        switch(v.getId()){
            case R.id.btn_insert://添加数据
                name=etName.getText().toString().trim();
                phoneNum=etPhoneNumber.getText().toString().trim();
                if(!TextUtils.isEmpty(name) && !TextUtils.isEmpty(phoneNum)){
                    ContentValues values = new ContentValues();
                    values.put("name",name);
                    values.put("phonenumber",phoneNum);
                    if(dao.insert(values) >0){
                        Toast.makeText(this,"联系方式添加成功",Toast.LENGTH_SHORT).show();
                        etName.setText("");
                        etPhoneNumber.setText("");
                    }
                }
                break;
            case R.id.btn_delete://删除数据
                name=etName.getText().toString().trim();
                //如果etName不为空则删除名字叫这个的记录
                if(!TextUtils.isEmpty(name)){
                    if(dao.deleteByName(name) > 0){
                        Toast.makeText(this,"删除联系人成功",Toast.LENGTH_SHORT).show();
                    }
                }else{
                    if(dao.deleteAll() >0){
                        Toast.makeText(this,"成功删除所有联系人",Toast.LENGTH_SHORT).show();
                    }
                }
                break;

            case R.id.btn_update://更新数据
                name=etName.getText().toString().trim();
                phoneNum=etPhoneNumber.getText().toString().trim();
                if(!TextUtils.isEmpty(name) && !TextUtils.isEmpty(phoneNum)){
                    ContentValues values = new ContentValues();
                    values.put("phonenumber",phoneNum);
                    if(dao.update(values,name)>0){
                        Toast.makeText(this,"修改联系人方式成功",Toast.LENGTH_SHORT).show();
                        etName.setText("");
                        etPhoneNumber.setText("");
                    }
                }
                break;

            case R.id.btn_query://查询数据
                Cursor cursor = dao.selectAll();
                if(cursor.getCount() == 0){
                    tvList.setText("");
                }else {
                    cursor.moveToFirst();
                    tvList.setText(cursor.getString(1) + ":" + cursor.getString(2));

                }

                while (cursor.moveToNext()){
                    tvList.append("\n" + cursor.getString(1) + ":" + cursor.getString(2) );
                }
                cursor.close();
                break;
        }
    }
}

上述代码用于实现联系人信息的添加、删除、修改和查询。当单击“添加”按钮时,会将输入的联系人姓名和联系方式存入数据库中。单击“删除”按钮时,将按两种情况分别进行处理:一种是输入了联系人姓名,则只会删除指定联系人的信息;另一种是联系人姓名为空,则会删除数据库中所有联系人的数据。单击“修改”按钮,会根据输入的联系人姓名修改对应的联系方式。单击“查询”按钮之后将会把所有联系人的具体信息展示在界面中的TextView控件里。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐