2011-11-12 34 views
22

Tôi đã đọc rất nhiều chủ đề, nhưng không thể tìm ra câu trả lời cho câu hỏi: có thể đọc và viết đồng thời không?Đọc và ghi SQLite đồng thời

Tôi có chuỗi nền cập nhật một số dữ liệu và giao diện người dùng cần một phần dữ liệu nhỏ được lưu trữ trong DB. Vì vậy, trong hoạt động UI thread SELECT được thực hiện. Nhưng nó chặn khi cập nhật đang diễn ra. Do đó, giao diện người dùng bị treo trong vài giây.

Có ai đã thành công khi đọc từ DB khi viết không?


Có thể đọc và ghi lên DB trên iPhone. Có phải lý do của sự khác biệt như vậy là trong việc triển khai đồng bộ của trình bao bọc trên các hàm sqlite tự nhiên?

+5

"Vì vậy, trong chuỗi giao diện người dùng, thao tác SELECT được thực hiện" -> thoát khỏi Giao diện người dùng. – hovanessyan

+2

Có hoạt động đơn giản như SELECT tên FROM some_table WHERE _id = Không hiển thị tên trong vài giây không tốt hơn nhiều so với đóng băng – HighFlyer

Trả lời

54

On SQLiteDatabases Android 3.0 trở lên hỗ trợ chế độ WAL (write-ahead logging):

Khi write-ahead khai thác gỗ không được bật (mặc định), nó không phải là có thể cho đọc và viết để xảy ra trên cơ sở dữ liệu tại cùng một thời điểm . Trước khi sửa đổi cơ sở dữ liệu, người viết ngầm mua một khóa độc quyền trên cơ sở dữ liệu để ngăn người đọc truy cập cơ sở dữ liệu cho đến khi ghi xong.

Ngược lại, khi ghi nhật ký ghi trước được bật, ghi hoạt động xảy ra trong tệp nhật ký riêng cho phép đọc đồng thời đồng thời. Trong khi đang viết, người đọc trên các chủ đề khác sẽ cảm nhận trạng thái của cơ sở dữ liệu như trước khi viết bắt đầu. Khi viết xong, người đọc trên các chủ đề khác sau đó sẽ nhận thức trạng thái mới của cơ sở dữ liệu.

http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#enableWriteAheadLogging()

Để bắt đầu một giao dịch trong chế độ WAL sử dụng beginTransactionNonExclusive() thay vì beginTransaction(). Trong khi beginTransaction() bắt đầu một giao dịch trong chế độ ĐỘC QUYỀN, beginTransactionNonExclusive() bắt đầu một trong chế độ NGAY

  • chế độ ĐỘC QUYỀN sử dụng ổ khóa độc quyền (http://www.sqlite.org/lockingv3.html#excl_lock) có nghĩa là không có kết nối cơ sở dữ liệu khác, ngoại trừ cho các kết nối read_uncommitted sẽ có thể đọc cơ sở dữ liệu và không có kết nối nào khác mà không có ngoại lệ sẽ có thể ghi cơ sở dữ liệu cho đến khi giao dịch hoàn tất
  • Chế độ IMMEDIATE sử dụng khóa được bảo lưu (http://www.sqlite.org/lockingv3.html#reserved_lock) nghĩa là không có kết nối cơ sở dữ liệu nào khác có thể ghi vào cơ sở dữ liệu hoặc thực hiện BEGIN IMMEDIATE hoặc BEGIN EXCLUSIVE Tuy nhiên, các quy trình khác có thể tiếp tục đọc từ cơ sở dữ liệu.

Nói cách đơn giản hơn: gọi beginTransactionNonExclusive() cho chế độ NGAY và chúng ta có thể đọc trong khi thread khác đang viết (tiểu bang trước khi giao dịch ghi bắt đầu bởi vì chúng tôi sẽ không sử dụng các kết nối read_uncommitted ->http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Dirty_reads).

+0

Tuyệt vời! Thông tin này rất quan trọng nhưng đã bị bỏ qua. Cảm ơn bạn đã trả lời chi tiết của bạn! – HighFlyer

+0

Chế độ WAL sẽ vô hiệu hóa tôi hỗ trợ tất cả các API nhỏ hơn API 16. Có giải pháp nào khác không? –

+6

Chế độ WAL được hỗ trợ từ API 11 trên (Tổ ong). Sự khác biệt giữa API 11 và API 16 là bạn có thể mở cơ sở dữ liệu trong chế độ WAL bằng API 16 bằng chế độ Context.MODE_ENABLE_WRITE_AHEAD_LOGGING trong khi bạn phải mở nó ở một trong các chế độ có sẵn trong API11-15 và sau đó chuyển sang chế độ WAL sử dụng SQLiteDatabase.enableWriteAheadLogging(). Mở ở chế độ WAL nhanh hơn đáng kể nhưng đó là những gì bạn có. Trước khi Honeycomb không chỉ có chế độ WAL có nghĩa là ứng dụng sẽ chạy chậm hơn nhưng có "nên" ít nhất là không có tác dụng phụ khác. –

1

Không thể đọc & ghi đồng thời. Tuy nhiên, nếu bạn có các lớp cơ sở dữ liệu SQLite được thiết lập đúng (một cá thể của các lớp trợ giúp DB &), các luồng khác nhau sẽ có thể lấy kết nối DB đồng bộ sao cho không có bất kỳ độ trễ đáng chú ý nào.

Nó cũng giống như bạn đang cố gắng làm công việc phụ trợ (ghi vào db) với chuỗi giao diện người dùng của bạn. Bạn không nên làm điều này. Tạo AsyncTask để xử lý việc này thay vì yêu cầu chuỗi giao diện người dùng của bạn xử lý nó.

Tham khảo tài liệu SQLiteOpenHelper. Đây là bài đăng trước đó nói về điều này: What are the best practices for SQLite on Android?

3

Bạn không thể đọc và viết cùng một lúc. SQLite là một cơ sở dữ liệu dựa trên tập tin không có máy chủ.

Từ SQLite FAQ:

"Khi quá trình bất kỳ muốn viết thì phải khóa toàn bộ tập tin cơ sở dữ liệu trong suốt thời gian cập nhật của nó. Nhưng điều đó thông thường chỉ mất một vài mili giây. Quá trình khác chỉ chờ đợi trên nhà văn để kết thúc sau đó tiếp tục về kinh doanh của họ. Các công cụ cơ sở dữ liệu SQL nhúng khác thường chỉ cho phép một quá trình duy nhất để kết nối với cơ sở dữ liệu cùng một lúc. "

+3

Được bỏ phiếu vì câu trả lời sai. Từ Honeycomb on (đã xuất hiện khi câu trả lời được đưa ra) có thể đọc/ghi "cùng một lúc" (xem câu trả lời của riêng tôi) –

+0

Tôi không thấy bất cứ điều gì trong câu hỏi ban đầu nói "trong Honeycomb" – dnuttle

+9

Câu hỏi đặt ra là: "có thể đọc và viết đồng thời không?", Câu trả lời của bạn là: "Bạn không thể đọc và viết cùng một lúc". Câu trả lời là sai bởi vì bạn có thể nếu bạn đang ở trên Honeycomb hoặc cao hơn. –

3

Bắt đầu với API 11 Android hỗ trợ chế độ WAL. Nó giữ dữ liệu gốc bị ảnh hưởng trong quá trình giao dịch, vì vậy các luồng khác có thể đọc khi giao dịch đang chạy. Bạn có thể kiểm tra bài viết của tôi để biết thêm chi tiết về chế độ WAL:

http://www.skoumal.net/en/parallel-read-and-write-in-sqlite/

Bạn cũng nên tránh chạy các truy vấn cơ sở dữ liệu trong thread UI. Nó luôn có thể trở nên chậm chạp và chặn giao diện người dùng của bạn.

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