Android SQLite 支持嵌套事务吗?
来源:互联网 发布:阿里云tv遥控器 编辑:程序博客网 时间:2024/05/23 11:50
Android SQLite相关java源码中多次提到支持 nested transaction。
而SQLite本身不支持嵌套事务,只能使用 savepoint 代替。 https://www.sqlite.org/lang_savepoint.html
嵌套事务即是类似于
BEGIN BEGIN ......
也许没有太多人会直接这样写,更多情况是,一个程序执行事务中调用了其他程序,而其他程序有自己的事务。
通过查看Android源码发现:
Android所谓的支持嵌套事务,只是屏蔽掉子事务的 begin end,只有最外层事务的begin end 有效。同时,子事务出错会导致整个嵌套事务出错,整个回滚。
当然,SQL SERVER好像也没有支持真正的嵌套事务,了解不太详细。
--------------------------------------------------------------------------------------
Android SQLite 关于嵌套事务的处理,均位于SqliteSession,多数数据库相关操作的调用流程均为 SQLiteDataBase --> SqliteSeesion --> SqliteConnectionPool --> SqliteConnection。稍后详细分析。只需知道,SQLiteDatabase.beginTransacion() 调用的是SQLiteSeesion.beginTransacion(),其他类似。如下
public void beginTransaction() { beginTransaction(null, true); } private void beginTransaction(SQLiteTransactionListener transactionListener, boolean exclusive) { acquireReference(); try { getThreadSession().beginTransaction( //--- 获取线程session,开始事务 exclusive ? SQLiteSession.TRANSACTION_MODE_EXCLUSIVE : SQLiteSession.TRANSACTION_MODE_IMMEDIATE, transactionListener, getThreadDefaultConnectionFlags(false /*readOnly*/), null); } finally { releaseReference(); } }--------------------------------------------------------------------
SQLiteSeesion中相关成员有以下需要注意:
private Transaction mTransactionPool; // 事务池 private Transaction mTransactionStack; // 事务栈 private static final class Transaction { public Transaction mParent; public int mMode; public SQLiteTransactionListener mListener; public boolean mMarkedSuccessful; public boolean mChildFailed; }可以猜想,事务栈、事务池其实是又 mParent联系起来的两条事务链。
先看 beginTransaction。
public void beginTransaction( /*省略参数*/ ) { throwIfTransactionMarkedSuccessful(); beginTransactionUnchecked( /*省略参数*/ ); } private void beginTransactionUnchecked( /*省略参数*/ ) { //... if (mTransactionStack == null) { // 事务栈为空 获取新连接 acquireConnection(null, connectionFlags, cancellationSignal); } try { if (mTransactionStack == null) { // 事务栈为空 执行“begin” switch (transactionMode) { // 事务栈不为空 直接略过 case TRANSACTION_MODE_IMMEDIATE: mConnection.execute("BEGIN IMMEDIATE;", null, cancellationSignal); break; case TRANSACTION_MODE_EXCLUSIVE: mConnection.execute("BEGIN EXCLUSIVE;", null, cancellationSignal); break; default: mConnection.execute("BEGIN;", null, cancellationSignal); break; } } //... 省略监听 transactionListener Transaction transaction = obtainTransaction(transactionMode, transactionListener);// 获取新的事务 transaction.mParent = mTransactionStack; // 将事务加入事务栈中 mTransactionStack = transaction; } finally { if (mTransactionStack == null) { releaseConnection(); // might throw } } }获取新事务obtainTransaction()如下
private Transaction obtainTransaction(int mode, SQLiteTransactionListener listener) { Transaction transaction = mTransactionPool; // 事务池中有事务,直接提取事务 if (transaction != null) { mTransactionPool = transaction.mParent; transaction.mParent = null; transaction.mMarkedSuccessful = false; transaction.mChildFailed = false; } else { transaction = new Transaction(); // 否则新建 } transaction.mMode = mode; transaction.mListener = listener; return transaction; }
由上可以看出,事务栈开始为空, 不断beginTransaction时会向事务栈中添加事务。那么事务池中的事务怎么来的呢?
在endTransaction中:
public void endTransaction(CancellationSignal cancellationSignal) { throwIfNoTransaction(); assert mConnection != null; endTransactionUnchecked(cancellationSignal, false); } private void endTransactionUnchecked(CancellationSignal cancellationSignal, boolean yielding) { final Transaction top = mTransactionStack; // 获取事务栈的top事务 boolean successful = (top.mMarkedSuccessful || yielding) && !top.mChildFailed; //... 省略监听 mTransactionStack = top.mParent; // 将top从事务栈中剔除 recycleTransaction(top); // 将top放入事务池中 if (mTransactionStack != null) { // 事务栈不为空 if (!successful) { // 如果未成功 将该事务的子事务置为失败 mTransactionStack.mChildFailed = true; } } else { try { // 事务栈为空 if (successful) { // 若成功 则提交 此时意味着所有事务都已经成功 mConnection.execute("COMMIT;", null, cancellationSignal); } else { // 不成功 就回滚 此时一个子事务未成功 则整个事务体系未成功 mConnection.execute("ROLLBACK;", null, cancellationSignal); } } finally { releaseConnection(); } } }
private void recycleTransaction(Transaction transaction) { transaction.mParent = mTransactionPool; // 其实就是将事务放入事务池 transaction.mListener = null; mTransactionPool = transaction; }
可以看到,事务池中的事务由事务栈中使用完毕的事务组成。不用的放入事务池,使用时直接提取,并将状态初始化。
也可以看出,事务池是为了避免Transaction多次new delete 的开销。事务栈中保存了正在执行的嵌套事务。
事务栈、事务池如下
setTransactionSuccessful()就比较简单了:
public void setTransactionSuccessful() { // 标记当前事务成功 throwIfNoTransaction(); throwIfTransactionMarkedSuccessful(); mTransactionStack.mMarkedSuccessful = true; // mTransactionStack指向的就是最近的一个事务 如图 }
执行beginTransaction():
当事务栈为空,说明没有外层事务,获取transaction,执行“BEGIN”,然后将transaction放入事务栈。
事务栈不为空,说明含有外层事务,获取transaction,不执行“BEGIN”,将transaction放入事务栈。
执行endTransaction():
查看successful,当本事务成功且内层事务成功,才算成功;将该事务从事务栈移入事务池。
当事务栈不为空,说明仍有外层事务,如果successful为价,将该事物置为子事务失败
当事务栈为空,说明已是最外层事务,successful则提交,否则回滚。
可以看到,嵌套事务中,无论哪一层事务出错,都会自其开始直至最外层事务标记为false,回滚。只有每一层都标记成功,最后才成功。
需要注意的是,yield会对嵌套事务successful的标记产生影响,使得当前事务无论如何都标记为成功。android不推荐在嵌套事务中使用yield。
- Android SQLite 支持嵌套事务吗?
- Android SQLite 支持嵌套事务吗?
- sqlite事务嵌套
- asp.net IBatisNet事务,支持事务嵌套
- android sqlite 事务
- android sqlite 事务
- Android SQLite事务操作
- Android 关于SQLite事务
- Android--SQLite事务
- android 之sqlite事务
- Sqlite笔记3--C#中事务支持
- Android中的sqlite事务操作
- android 实现SQLite开启事务
- Android中SQLite使用事务
- android sqlite数据库的事务
- Android SQLite数据库—事务
- android sqlite CRUD 查询 事务
- android sqlite支持的数据类型
- 学会换位思考,你的世界才会简单,人心简单就幸福
- 关于避免fragment重复加载
- 深入浅出pmp 读书笔记
- ios8 CLLocationManager开发笔记一 定位
- Java 内存分配全面浅析
- Android SQLite 支持嵌套事务吗?
- iOS7的适配
- Java 程序里的内存泄漏
- ios Map 开发笔记二 地图
- 眼球上的科技 隐形眼镜可以当电视看
- HttpContext.Current并非无处不在
- iOS推送:Java服务器端发送表情(绘文字)
- Android 学习笔记9:高级控件
- ios Map 开发笔记三 3D地图