Android入门第54天-SQLite中的Transaction

简介

上一篇我们完整的介绍了SQLite在Android中如何使用,今天我们要来讲一下“Transaction“即事务这个问题。

我们经常在编程中会碰到这样的业务场景:

Android入门第54天-SQLite中的Transaction_第1张图片

  •  没问题一系列有业务关联性表操作的数据一起提交;
  • 事务中只要有一步有问题,那么就认为在此过程中的每一步都失败,为了保证业务数据的完整性所以每一步的表操作数据都不成功-即:回滚;

在SQLite中,我们使用:

  • dbOpenHelper.getWritableDatabase().beginTransaction()来开启事务;
  • dbOpenHelper.getWritableDatabase().setTransactionSuccessful()申明整个事务成功;

因此我们会把所有的单条DB操作如果有问题都需要抛出Exception,然后在外部调用的块中以“beginTransaction"为起初步骤,全部步骤成功后我们会调用setTransactionSuccessful();那么整个DB事务就会被提交。

否则在beginTransaction后的每一步db操作都不会成功。

如果我们没有在一开始就以beginTransaction()开头,那么每一个单独的db操作如:db.insert()这样的一条语句只要不抛错就会自动被提交到数据库,并且如果有一系列关联的db操作动作的话不使用beginTransaction开头的话那么它们是不含事务操作的。

课程目标

Android入门第54天-SQLite中的Transaction_第2张图片

首先我们在这个APP启动时会创建这么三个表(MAC下我用了SQLite Explorer-比我在前一篇介绍的SQLite Manager还要好用、还免费,真心在MAC下面不少免费的东西比Windows下的工具要好用,可能真的是预收费?我这边又想放出那个“吼叫着的土拨鼠”的表情了。)

Android入门第54天-SQLite中的Transaction_第3张图片

 然后,在界面上输入学号、班级号然后模拟两个场景:

  1. 以beginTransaction起始以setTransactionSuccessful结束包裹的往t_student、t_class、t_student_class三张表里插数据,一切无误的情况下它会把三张表都插进数据;
  2. 以beginTransaction起始往t_student、t_class、t_student_class三张表里插数据,一切无误的情况下不调用setTransactionSuccessful来模拟事务中有失败场景,然后去表内查找记录,我们会发觉往这三个表里没有能够插入任何新的数据,因为只要没有调用(跳过)setTransactionSuccessful,任何一张表里都不会有数据(即被回滚掉了);

下面放出相应的代码

全代码

建表语句

private static final String DB_CREATE_STD_CLASS = "CREATE TABLE t_student_class(student_id VARCHAR(20), class_id VARCHAR(6),"+
                " PRIMARY KEY(student_id, class_id)"+
                ");";
private static final String DB_CREATE_STD = "CREATE TABLE t_student(student_id VARCHAR(20), student_name VARCHAR(20),"+
                " PRIMARY KEY(student_id)"+
                ");";
private static final String DB_CREATE_CLASS = "CREATE TABLE t_class(class_id VARCHAR(20),"+
                " PRIMARY KEY(class_id)"+
                ");";

 前端UI




    


    

    

    

    

StudentBean

package org.mk.android.demo.transaction;

import java.io.Serializable;

public class StudentBean implements Serializable {
    private String studentId="";
    private String studentName="";

    public String getStudentId() {
        return studentId;
    }

    public void setStudentId(String studentId) {
        this.studentId = studentId;
    }

    public String getStudentName() {
        return studentName;
    }

    public void setStudentName(String studentName) {
        this.studentName = studentName;
    }
}

ClassBean

package org.mk.android.demo.transaction;

import java.io.Serializable;

public class ClassBean implements Serializable {
    private String classId="";

    public String getClassId() {
        return classId;
    }

    public void setClassId(String classId) {
        this.classId = classId;
    }
}

StudentClassMappingBean

package org.mk.android.demo.transaction;

import java.io.Serializable;

public class StudentClassMappingBean implements Serializable {
    private String studentId = "";
    private String classId = "";

    public String getStudentId() {
        return studentId;
    }

    public void setStudentId(String studentId) {
        this.studentId = studentId;
    }

    public String getClassId() {
        return classId;
    }

    public void setClassId(String classId) {
        this.classId = classId;
    }
}

DBAdapter

package org.mk.android.demo.transaction;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;

public class DBAdapter {
    private static final String TAG = "DemoSQLiteTransaction";
    private static final String DB_NAME = "student.db";
    private static final int DB_VERSION = 2;


    private SQLiteDatabase db;
    private Context context = null;
    private DBOpenHelper dbOpenHelper;

    public DBAdapter(Context ctx) {
        context = ctx;
    }

    public void close() {
        try {
            if (db != null) {
                db.close();
                db = null;
            }
        } catch (Exception e) {
        }
    }

    public void open()  {
        dbOpenHelper = new DBOpenHelper(context, DB_NAME, null, DB_VERSION);
        try {
            db = dbOpenHelper.getWritableDatabase();
        } catch (SQLiteException ex) {
            Log.e(TAG, ">>>>>>open db error: " + ex.getMessage(), ex);

        }
    }
    public void addStudentAndClass(StudentBean stdBean,ClassBean clsBean)throws Exception{
        try {
            db.beginTransaction();
            ContentValues stdValues=new ContentValues();
            stdValues.put("student_id", stdBean.getStudentId());
            stdValues.put("student_name", stdBean.getStudentName());

            ContentValues classValues=new ContentValues();
            classValues.put("class_id", clsBean.getClassId());

            ContentValues stdClassValues=new ContentValues();
            stdClassValues.put("student_id", stdBean.getStudentId());
            stdClassValues.put("class_id", clsBean.getClassId());

            db.insert("t_student", null, stdValues);
            db.insert("t_class", null, classValues);
            //throw new Exception("mk define the customized exception");
            db.insert("t_student_class", null, stdClassValues);
            db.setTransactionSuccessful();
        } catch (Exception e) {
            Log.e(TAG, "addItem error: " + e.getMessage(), e);
            throw new Exception("addItem error: " + e.getMessage(), e);
        }finally {
            db.endTransaction();
        }
    }


    public List queryAll() {
        List stdClassMappingList = new ArrayList();
        try {
            StringBuilder sqlStr = new StringBuilder();
            sqlStr.append("select student_id, class_id from t_student_cass");
            Cursor cur = db.rawQuery(sqlStr.toString(), null);
            while (cur.moveToNext()) {
                String studentId = cur.getString(cur.getColumnIndexOrThrow("student_id"));
                String classId = cur.getString(cur.getColumnIndexOrThrow("classId"));
                StudentClassMappingBean stdClassMappingBean=new StudentClassMappingBean();
                stdClassMappingBean.setStudentId(studentId);
                stdClassMappingBean.setClassId(classId);
                stdClassMappingList.add(stdClassMappingBean);
            }
        } catch (Exception e) {
            Log.e(TAG, ">>>>>>queryAll error: " + e.getMessage(), e);
        }
        return stdClassMappingList;
    }

    private static class DBOpenHelper extends SQLiteOpenHelper {

        public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
            super(context, name, factory, version);
        }

        private static final String DB_CREATE_STD_CLASS = "CREATE TABLE t_student_class(student_id VARCHAR(20), class_id VARCHAR(6),"+
                " PRIMARY KEY(student_id, class_id)"+
                ");";
        private static final String DB_CREATE_STD = "CREATE TABLE t_student(student_id VARCHAR(20), student_name VARCHAR(20),"+
                " PRIMARY KEY(student_id)"+
                ");";
        private static final String DB_CREATE_CLASS = "CREATE TABLE t_class(class_id VARCHAR(20),"+
                " PRIMARY KEY(class_id)"+
                ");";
        @Override
        public void onCreate(SQLiteDatabase db) {
            Log.i(TAG, ">>>>>>execute create table" );
            db.execSQL(DB_CREATE_STD_CLASS);
            db.execSQL(DB_CREATE_STD);
            db.execSQL(DB_CREATE_CLASS);
            Log.i(TAG, ">>>>>>execute create table successfully" );
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int _oldVersion, int _newVersion) {
            //db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE);
            //onCreate(_db);
            db.execSQL("DROP TABLE IF EXISTS t_student");
            db.execSQL("DROP TABLE IF EXISTS t_class");
            db.execSQL("DROP TABLE IF EXISTS t_student_class");
            onCreate(db);

        }
    }
}

MainActivity

package org.mk.android.demo.transaction;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends AppCompatActivity {
    private SQLiteDatabase db;
    private Context context;
    private DBAdapter dbAdapter;
    Button buttonAddItem;
    EditText editStudentId;
    EditText editClassId;
    private static final String TAG = "DemoSQLiteTransaction";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        context = getApplicationContext();
        dbAdapter = new DBAdapter(context);
        buttonAddItem=(Button)findViewById(R.id.buttonAddItem);
        editStudentId=(EditText)findViewById(R.id.editStudentId);
        editClassId=(EditText)findViewById(R.id.editClassId);
        buttonAddItem.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String studentId=editStudentId.getText().toString();
                String classId=editClassId.getText().toString();
                try{
                    dbAdapter.open();
                    StudentBean stdBean=new StudentBean();
                    ClassBean clsBean=new ClassBean();
                    stdBean.setStudentId(studentId);
                    stdBean.setStudentName(studentId);
                    clsBean.setClassId(classId);
                    dbAdapter.addStudentAndClass(stdBean,clsBean);
                    Log.i(TAG,">>>>>>insert success");
                }catch(Exception e){
                    Log.e(TAG,">>>>>>addItem error: "+e.getMessage(),e);
                }finally{
                    dbAdapter.close();
                }
            }
        });
        dbAdapter.open();
    }

    @Override
    protected void onStop() {
        super.onStop();
        dbAdapter.close();
    }
}

运行效果

一切DB操作步骤在无误情况下且正确提交了事务

我们分别输入:

  1. student_id:101, classId:1
  2. student_id:102, classId:1
  3. student_id:103, classId:4

Android入门第54天-SQLite中的Transaction_第4张图片

 正确提交数据后我们从Device File Explorer中脱机出来student.db用SQLite Explorer打开,发觉数据正确进入了3张表中

Android入门第54天-SQLite中的Transaction_第5张图片

Android入门第54天-SQLite中的Transaction_第6张图片

Android入门第54天-SQLite中的Transaction_第7张图片 注释掉DBAdapter里的setTransactionSuccessful语句再操作

我们把这一处代码中的setTransactionSuccessful注释掉

Android入门第54天-SQLite中的Transaction_第8张图片

重新运行起APP来然后在界面中输入:

Android入门第54天-SQLite中的Transaction_第9张图片

然后我们脱机出我们的student.db并用SQLite Explorer打开这个文件来看

Android入门第54天-SQLite中的Transaction_第10张图片Android入门第54天-SQLite中的Transaction_第11张图片

Android入门第54天-SQLite中的Transaction_第12张图片

我们可以看到,我们新输入的记录由于没有正确setTransactionSuccessful,因此这条数据就没有被插入SQLite中去。

自己动一下手试试吧。

你可能感兴趣的:(Android从入门到精通,android,sqlite,android,sqlite,androi,入门,android,教程)