編輯:關於Android編程
Android SQLite相關java源碼中多次提到支持 nested transaction。
而SQLite本身不支持嵌套事務,只能使用 savepoint 代替。
嵌套事務即是類似於
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; }
在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。
使用 Qt 為 Android 開發應用時,有時我們的應用會攜帶一些資源文件,如 png 、 jpg 等,也可能有一些配置文件,如 xml 等,這些文件放在哪裡呢?
AndroidN 除了提供諸多新特性和功能外,還對系統和 API 行為做出了各種變更。本文重點介紹您應該了解並在開發應用時加以考慮的一些重要變更。如果您之前發布過 And
本文實例講述了Android ProgressBar圓形進度條顏色設置方法。分享給大家供大家參考,具體如下:你是不是還在為設置進度條的顏色而煩惱呢……別著急,且看如下如何
有了前面幾篇博文作為基礎(《Android之——AIDL小結》、《Android之——AIDL深入》、《Android之&