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