Android入门第54天-SQLite中的Transaction
Posted TGITCIC
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android入门第54天-SQLite中的Transaction相关的知识,希望对你有一定的参考价值。
简介
上一篇我们完整的介绍了SQLite在android中如何使用,今天我们要来讲一下“Transaction“即事务这个问题。
我们经常在编程中会碰到这样的业务场景:
- 没问题一系列有业务关联性表操作的数据一起提交;
- 事务中只要有一步有问题,那么就认为在此过程中的每一步都失败,为了保证业务数据的完整性所以每一步的表操作数据都不成功-即:回滚;
在SQLite中,我们使用:
- dbOpenHelper.getWritableDatabase().beginTransaction()来开启事务;
- dbOpenHelper.getWritableDatabase().setTransactionSuccessful()申明整个事务成功;
因此我们会把所有的单条DB操作如果有问题都需要抛出Exception,然后在外部调用的块中以“beginTransaction"为起初步骤,全部步骤成功后我们会调用setTransactionSuccessful();那么整个DB事务就会被提交。
否则在beginTransaction后的每一步db操作都不会成功。
如果我们没有在一开始就以beginTransaction()开头,那么每一个单独的db操作如:db.insert()这样的一条语句只要不抛错就会自动被提交到数据库,并且如果有一系列关联的db操作动作的话不使用beginTransaction开头的话那么它们是不含事务操作的。
课程目标
首先我们在这个APP启动时会创建这么三个表(MAC下我用了SQLite Explorer-比我在前一篇介绍的SQLite Manager还要好用、还免费,真心在MAC下面不少免费的东西比Windows下的工具要好用,可能真的是预收费?我这边又想放出那个“吼叫着的土拨鼠”的表情了。)
然后,在界面上输入学号、班级号然后模拟两个场景:
- 以beginTransaction起始以setTransactionSuccessful结束包裹的往t_student、t_class、t_student_class三张表里插数据,一切无误的情况下它会把三张表都插进数据;
- 以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
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="student_id:" />
<EditText
android:id="@+id/editStudentId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="studentId" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="classId:" />
<EditText
android:id="@+id/editClassId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="classId" />
<Button
android:id="@+id/buttonAddItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="添加一条记录" />
</LinearLayout>
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<StudentClassMappingBean> queryAll()
List<StudentClassMappingBean> stdClassMappingList = new ArrayList<StudentClassMappingBean>();
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操作步骤在无误情况下且正确提交了事务
我们分别输入:
- student_id:101, classId:1
- student_id:102, classId:1
- student_id:103, classId:4
正确提交数据后我们从Device File Explorer中脱机出来student.db用SQLite Explorer打开,发觉数据正确进入了3张表中
注释掉DBAdapter里的setTransactionSuccessful语句再操作
我们把这一处代码中的setTransactionSuccessful注释掉
重新运行起APP来然后在界面中输入:
然后我们脱机出我们的student.db并用SQLite Explorer打开这个文件来看
我们可以看到,我们新输入的记录由于没有正确setTransactionSuccessful,因此这条数据就没有被插入SQLite中去。
自己动一下手试试吧。
以上是关于Android入门第54天-SQLite中的Transaction的主要内容,如果未能解决你的问题,请参考以下文章
Android入门第41天-Android中的Service(bindService)
Android入门第40天-Android中的Service(SimpleStartService)
Android入门第57天-使用OKHttp多线程制作像迅雷一样的断点续传功能
Android入门第42天-Android中的Service(IntentService)