事務是數據庫保證數據唯一性和一致性的技術,對於數據庫一個或一組寫操作要保證是一個原子操作就需要使用事務,android使用事務的常見形式如下:
SQLiteDatabase db = null;
...
db.beginTransaction();
try {
db.setTransactionSuccessful();
...
} finally {
db.endTransaction();
}
那麼db.beginTransaction是一個什麼操作? 我們來看下SQLiteDatabase的源碼:
/**
* Begins a transaction in EXCLUSIVE mode.
* <p>
* Transactions can be nested.
* When the outer transaction is ended all of
* the work done in that transaction and all of the nested transactions will be committed or
* rolled back. The changes will be rolled back if any transaction is ended without being
* marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
*/
public void beginTransaction() {
beginTransaction(null /* transactionStatusCallback */, true);
}
/**
* Begins a transaction in IMMEDIATE mode.
*Transactions can be nested. When
* the outer transaction is ended all of the work done in that transaction
* and all of the nested transactions will be committed or rolled back. The
* changes will be rolled back if any transaction is ended without being
* marked as clean (by calling setTransactionSuccessful). Otherwise they
* will be committed.
*/
public void beginTransactionNonExclusive() {
beginTransaction(null /* transactionStatusCallback */, false);
}
從註釋中可以看到beginTransaction的調用使用EXCLUSIVE mode, beginTransactionNonExclusive使用IMMEDIATE mode,以上兩個方法都是調用SQLiteDatabase的私有方法beginTransaction,兩個方法不同之處在於第二個實參true|false, 這個私有方法源碼:private void beginTransaction(SQLiteTransactionListener transactionListener,
boolean exclusive) {
verifyDbIsOpen();
lockForced(BEGIN_SQL);
boolean ok = false;
try {
...
// This thread didn't already have the lock, so begin a database
// transaction now.
if (exclusive && mConnectionPool == null) {
execSQL("BEGIN EXCLUSIVE;");
} else {
execSQL("BEGIN IMMEDIATE;");
}
...
} finally {
if (!ok) {
// beginTransaction is called before the try block so we must release the lock in
// the case of failure.
unlockForced();
}
}
}
當形參exclusive爲true並且mConnectionPool==null是執行:execSQL("BEGIN EXCLUSIVE;"); false執行execSQL("BEGIN IMMEDIATE;");
BEGIN EXCLUSIVE:當前事務在沒有結束之前任何android中的其他線程或進程都無法對數據庫進行讀寫操作。
BEGIN IMMEDIATE:確保android中其他線程或者進程之間讀取數據不能修改數據庫。
爲什麼需要判斷mConnectionPool==null這個條件,如果當mConnectionPool!=null 表示調用了enableWriteAheadLogging,也就是使用了WAL MODE。 使用WAL模式是能夠提高併發性,讀與寫互不阻塞,而執行BEGIN EXCLUSIVE卻降低了併發,互相矛盾,所以當以上兩個條件都成立的情況下執行BEGIN EXCLUSIVE。
關於WAL模式會在另外一個blog講解。