2014-09-29 28 views
5

được sửa đổi:
Vâng, SQLite doesn't support giao dịch lồng nhau, nhưng docs tuyên bố rằng SQLiteDatabase làm.
Tình huống
Tôi có phương thức chứa giao dịch và tôi cần gọi phương thức này từ giao dịch khác.
Ngoài ra - cả hai giao dịch đều hoạt động trên cùng một bộ hồ sơ, nhưng cập nhật các cột khác nhau.
Vấn đề
Có vẻ như kết quả của các giao dịch bên ngoài của tôi bị hủy bởi bên trong, cả hai đều được đánh dấu sạch sẽ bằng setTransactionSuccessful() và kết thúc bằng endTransaction() - Tôi đã kiểm tra điều này.
Câu hỏi
- Bất kỳ ý tưởng nào tại sao điều này có thể xảy ra?
- Có cách nào được khuyến nghị để thực hiện các giao dịch như vậy không?SQLiteDatabase giao dịch lồng nhau và workaround

Trả lời

5

Bạn có thể giao dịch tổ với các API sqlite Android, với caveats:

giao dịch có thể được lồng vào nhau. Khi giao dịch bên ngoài kết thúc tất cả công việc được thực hiện trong giao dịch đó và tất cả các giao dịch lồng nhau sẽ được cam kết hoặc quay trở lại. Các thay đổi sẽ được khôi phục nếu bất kỳ giao dịch nào kết thúc mà không được đánh dấu là sạch (bằng cách gọi setTransactionSuccessful). Nếu không, họ sẽ được cam kết.

Cách tiếp cận khác mà tôi thấy được sử dụng với sqlite nói chung là chuyển một tham số boolean isInTransaction cho biết phương thức được gọi là tự xử lý giao dịch hoặc cho người gọi xử lý giao dịch.

+0

Cảm ơn. [Documents] (http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#beginTransaction()) cho phép giao dịch lồng nhau, nhưng có vẻ như kết quả giao dịch bên ngoài của tôi bằng cách nào đó bị hủy bỏ bởi một bên trong (mỗi giao dịch giao dịch với cùng một bộ hồ sơ, nhưng cập nhật các cột khác nhau)./Bằng cách này, bạn có biết làm thế nào điều đó có thể xảy ra không?/ Bây giờ tôi sử dụng giao dịch có điều kiện (tương tự như đề xuất của bạn) và vì vậy tôi sẽ gắn bó với nó – sberezin

5

"Giao dịch Android lồng nhau" làm không sử dụng SQLites lồng nhau giao dịch/điểm hỗ trợ.

Thay vì giao dịch Android lồng nhau ngăn chặn biểu hiện giao dịch SQLite. Giao dịch lồng nhau không thể tự động khôi phục vì nó không tồn tại ngoài giao dịch bên ngoài. Điều này có thể be seen here với bảo vệ mTransactionStack == null.

Cách duy nhất để thực sự hỗ trợ lồng giao dịch - mà SQLite không hỗ trợ, chỉ cần không phải với BEGIN/COMMIT - là để tự sử dụng các lệnh savepoint/RELEASE. Tất nhiên, việc thiết kế mã để không dựa vào điều này sẽ loại bỏ việc quản lý thủ công bổ sung mà điều này đòi hỏi.

(Tôi có lẽ sẽ di chuyển tất cả các công việc giao dịch ra khỏi các hoạt động cá nhân thực tế, để lại công tác quản lý để người gọi cấp cao;. Làm việc này khá tốt cho một mẫu UOW, nhưng có thể không phải lúc nào được áp dụng)

2

Bây giờ tôi đã kết thúc với thiết kế phương pháp đối xứng (tương tự như đề xuất laalto) cung cấp công việc chính xác. Đó là một cách giải quyết rõ ràng "chuyển đổi" các giao dịch lồng nhau thành một giao dịch duy nhất.
Bây giờ tôi có thể gọi riêng cho họ hoặc từ người khác (không có phản ứng phụ mà tôi vẫn không hiểu).
Ở đây là:

public void method1() { 
    SQLiteDatabase db = dbhelper.getWritableDatabase(); 

    boolean doAsTransaction = !db.inTransaction(); 

    if (doAsTransaction) 
     db.beginTransaction(); 

    try { 
     // ... 
     if (doAsTransaction) 
      db.setTransactionSuccessful(); 

    } catch (Exception e) { 
     // ... 

    } finally { 
     // ... 
     if (doAsTransaction) 
      db.endTransaction(); 
    } 
} 


public void method2() { 
    SQLiteDatabase db = dbhelper.getWritableDatabase(); 

    boolean doAsTransaction = !db.inTransaction(); 

    if (doAsTransaction) 
     db.beginTransaction(); 

    try { 
     // ... 
     method1(); 
     if (doAsTransaction) 
      db.setTransactionSuccessful(); 

    } catch (Exception e) { 
     // ... 

    } finally { 
     // ... 
     if (doAsTransaction) 
      db.endTransaction(); 
    } 
} 
0

Bạn có thể thực hiện giao dịch lồng nhau bằng cách sử dụng SQL liệu cho savepoints trong execSQL() theo cách này:

db.execSql("SAVEPOINT test"); // declare savepoint 
// ... do some operations 
db.execSql(";ROLLBACK TO test"); // rollback 
db.execSql("RELEASE test"); // save changes 

chấm phẩy trước mặt ROLLBACK là cần thiết, bởi vì không có nó cơ sở dữ liệu Android khung sẽ cố gắng gọi endTransaction(). Xem mã của các phương thức android.database.sqlite.SQLiteSession#executeSpecialandroid.database.sqlite.SQLiteSession#execute để biết chi tiết.

Các vấn đề liên quan