2025-03-25

介紹:數據庫事務是由一組數據庫操作序列組成,事務作為一個整體被執行。

事務的原子性:包含在其中的對數據庫的操作序列最終要麼全部執行,要麼全部不執行。當全部執行時,事務對數據庫的修改將生效;當全部不執行時,數據庫維持原有的狀態,不會被修改。

問題:最近在做一個從sdcard導入數據到數據庫的功能,當導入失敗時,數據庫要恢復到導入前的狀態。使用數據庫事務處理能很好地滿足到我們的需求。

我們知道Android平臺上使用的sqlite數據庫是支持事務處理功能的,實現的代碼如下:

view plain
SQLiteDatabase db =mOpenHelper.getWritableDatabase(); 
                   db.beginTransaction();//開始事務 
//進行insertdelete update等數據庫操作 
db.setTransactionSuccessful();//設置事務標記為Successful 
db.endTransaction();//提交事務 

可是,對於已經封裝成ContentProvider的Sqlite我們應該如何讓其支持事務處理功能呢?

解決辦法:查看ContentProvider的API說明文檔,我們驚喜地發現applyBatch(String authority,ArrayList<ContentProviderOperation> operations)這個方法,難道隻需要直接使用這個方法就可以實現事務瞭?

謹慎起見我們先來看看ContentProvider的源碼,最後追蹤到這個方法:

view plain
public ContentProviderResult[]applyBatch(ArrayList<ContentProviderOperation> operations) 
            throwsOperationApplicationException { 
       final int numOperations = operations.size(); 
       final ContentProviderResult[] results = newContentProviderResult[numOperations]; 
       for (int i = 0; i < numOperations; i++) {//遍歷數據庫操作序列 
            results[i] =operations.get(i).apply(this, results, i);//執行數據庫操作 
       } 
       return results;//返回結果 
   } 


從上面的代碼中,我們找不到和db.beginTransaction()、db.endTransaction()相似的方法,也就是說,這個方法隻是進行簡單的批處理,並沒有保障這些數據庫操作的原子性。

好吧。我們稍微動下腦筋,覆寫ContentProvider的applyBatch()方法,為其添加事務處理功能。代碼如下:

view plain
@Override 
publicContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation>operations) 
            throwsOperationApplicationException{ 
          SQLiteDatabasedb = mOpenHelper.getWritableDatabase(); 
          db.beginTransaction();//開始事務 
          try{ 
                   ContentProviderResult[]results = super.applyBatch(operations); 
                   db.setTransactionSuccessful();//設置事務標記為successful 
                   returnresults; 
          }finally { 
                   db.endTransaction();//結束事務 
          } 


然後,我們該如何使用這個applyBatch()方法呢?applyBatch()的第一個參數實現事務的Provider的authority屬性,第二個參數是數據庫操作序列,構建數據庫操作的對象使用瞭builder設計模式,下面是一個使用applyBatch()的例子:

view plain
ArrayList<ContentProviderOperation>ops = new ArrayList<ContentProviderOperation>(); 
ops.add(ContentProviderOperation.newDelete(Person.CONTENT_URI).build());//添加一個刪除Person表的操作 
ops.add(ContentProviderOperation.newInsert(Home.CONTENT_URI).withValues(values).build());//添加一條記錄到Home表 
getContentResolver().applyBatch(PROVIDER.AUTHORITY,ops);//處理事務 

總結:

1、sqlite支持事務處理操作

2、對於封裝成ContentProvider的sqlite數據庫,我們可以通過覆寫ContentProvider的applyBatch(Stringauthority, ArrayList<ContentProviderOperation> operations)方法來實現對事務處理的支持

作者“lzc的專欄”

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *