2011-10-31 40 views
10

Tôi có một ứng dụng (Android 2.2 Google API Level 8) có nhiều hoạt động kéo dữ liệu từ nhà cung cấp nội dung (chỉ truy cập cơ sở dữ liệu SELECT). Nó cũng có một dịch vụ với hàng đợi nhiệm vụ chặn trung tâm chấp nhận bất kỳ tác vụ ghi cơ sở dữ liệu nào; các hoạt động có thể kích hoạt một yêu cầu dịch vụ (Theo mục đích), đặt một nhiệm vụ trên hàng đợi chặn để truy xuất tuần tự bởi một luồng và thực hiện đơn lẻ. Cơ sở dữ liệu khoảng 4mb.lỗi "sqlite" của cơ sở dữ liệu android bị khóa mặc dù sử dụng nhà cung cấp nội dung và truy cập cơ sở dữ liệu tuần tự

Có một trình trợ giúp cơ sở dữ liệu duy nhất mà dịch vụ sử dụng để gọi các phương thức tương tác với cơ sở dữ liệu bao gồm viết thư cho nó; tất cả các ghi SQL được thực hiện bên trong trình trợ giúp cơ sở dữ liệu.

  • Tất cả ghi cơ sở dữ liệu đều được bao quanh bởi giao dịch.
  • Tất cả các lần đọc cơ sở dữ liệu đều có con trỏ đóng ở cuối phương thức.
  • Không có hoạt động nào có xử lý đối tượng cơ sở dữ liệu, chúng chỉ có thể giao tiếp thông qua nhà cung cấp nội dung hoặc dịch vụ.
  • Bất kỳ tác vụ nào của AlarmManager được kích hoạt - như Hoạt động - chỉ sử dụng dịch vụ để bật tác vụ thích hợp lên hàng đợi.
  • Dịch vụ là lớp duy nhất có trình điều khiển cho trình trợ giúp cơ sở dữ liệu.
  • Tất cả ghi cơ sở dữ liệu chỉ được thực hiện thông qua tác vụ được đặt trên hàng đợi; Tôi đã hết sức kiểm tra việc thực hiện tác vụ đó tuần tự được nhận thức rõ ràng về nó là điều cần thiết để tránh đồng thời ghi vào cơ sở dữ liệu SQLite.

Trong khi chạy các thao tác tác vụ, tôi liên tục nhận được một hoặc hai lỗi "cơ sở dữ liệu bị khóa" khi cố ghi vào cơ sở dữ liệu được kích hoạt bởi thực hiện nhiệm vụ 'bắt đầu giao dịch'.

Khi cố gắng theo dõi nguồn khóa, tôi thấy rằng sử dụng dbhelper.inTransaction(), dbhelper.isLockedByThisThread(), dbhelper.isLockedByOtherThread() không hỗ trợ vì chúng không chỉ ra khóa cơ sở dữ liệu không mong muốn.

Những gì tôi đã tìm thấy đã làm việc trong việc phát hiện khóa sớm là tạo phương thức với beginTransaction() và setTransactionSuccessful mà không có bất kỳ mã ghi SQL thực tế nào, trong khối try try để đăng nhập vấn đề - luôn được kích hoạt bởi beginTransaction() .

Tôi đặt bẫy khóa cơ sở dữ liệu này ở bên cạnh mỗi phương thức nhiệm vụ hàng đợi chặn trong kỳ vọng/hy vọng rằng tôi sẽ tìm thấy thủ phạm đơn lẻ rời cơ sở dữ liệu ở trạng thái bị khóa sau khi hoàn tất. Tôi không thể tìm thấy một thủ phạm nhất quán. Sau khi khoan qua từ khi bắt đầu cuộc gọi đến cơ sở dữ liệu, tôi thấy rằng khóa cơ sở dữ liệu có thể xuất hiện có vẻ ngoài màu xanh mà không bị khóa bởi tác vụ trước đó (Tất cả các tác vụ này chạy theo trình tự dưới cùng một chuỗi đơn).

Sau khi xem xét một số trải nghiệm của người khác với các vấn đề về khóa cơ sở dữ liệu tôi đã cố gắng đóng kết nối cơ sở dữ liệu ngay sau khi giao dịch đã hoàn thành trên tất cả các tác vụ, nhưng điều này không giúp được gì . Đã cố gắng thêm một giấc ngủ giữa mỗi lần thực hiện nhiệm vụ; chưa được kiểm tra đầy đủ nhưng thường thấy rằng độ trễ 3 giây trở lên dường như dừng các khóa cơ sở dữ liệu xuất hiện. Đã vô hiệu hóa việc vô hiệu hoá các trình quản lý cảnh báo đã kích hoạt - không tạo ra bất kỳ sự khác biệt nào.

Hiển thị tôi có là một số hình thức nhiệm vụ bảo trì bên ngoài ứng dụng của tôi đang rơi vào và khóa cơ sở dữ liệu định kỳ - có thể trì hoãn việc ghi nhật ký.Rõ ràng là tôi ít quan tâm đến việc thiết lập một chậm trễ xử lý nhiệm vụ vì vậy tôi đang xem xét việc có một khóa cơ sở dữ liệu thử lại hàng đợi nhiệm vụ để reattempt cơ sở dữ liệu bằng văn bản khi cần thiết; nhiều người thích giải quyết nhưng đang hết ý tưởng.

Có ai có thể nghĩ ra một số nguyên tắc hoặc gotcha mà tôi đã bỏ lỡ không?

Thực tế có bình thường trong các cơ sở dữ liệu SQLite lớn hơn và Android mà bạn sẽ nhận được các khóa cơ sở dữ liệu không thường xuyên?

Cảm ơn

+0

Có phải đọc (chọn) đến cơ sở dữ liệu được tuần tự hóa thông qua cơ chế xếp hàng hoặc có thể đọc chồng chéo với một trong các giao dịch viết của bạn không? Nếu điều này xảy ra hơn cam kết có thể thất bại. Xem chương 7 ở đây http://www.sqlite.org/lockingv3.html – Stefan

Trả lời

0

tôi sẽ kiểm tra nếu một số hoạt động mà các cuộc gọi DB hoặc gọi hoạt động khác mà các cuộc gọi DB, chỉ có một ví dụ. Ngoài ra nó có thể khóa chính nó, theo một nghĩa nào đó.

+0

Vì vậy, trong trường hợp của tôi (hơi khác một chút so với mô tả ở trên), tôi có hai hành động xảy ra tuần tự, nhưng không quá dài sau một lần khác. Người dùng thực hiện bước một, cam kết (điều này làm việc tốt) nhưng cái thứ hai cam kết và bị khóa. Điều này xảy ra ít hơn 5% thời gian và không có mã nền nào khác có thể tương tác tại thời điểm đó – Pyrodante

7

SQLite đảm bảo truy cập tuần tự từ nhiều chủ đề miễn là bạn sử dụng một kết nối cơ sở dữ liệu duy nhất. Bạn mở và đóng kết nối cơ sở dữ liệu ở đâu và ở đâu?

Tôi thường khuyên bạn nên mở cơ sở dữ liệu một lần khi khởi động và không bao giờ đóng nó. Không có lợi ích gì khi đóng, vì bản chất giao dịch của SQLite có nghĩa là các ghi được xóa đi để lưu trữ liên tục càng sớm càng tốt.

0

Liên quan đến

Có trong thực tế bình thường trong Android và cơ sở dữ liệu SQLite lớn hơn mà bạn sẽ nhận được ổ khóa cơ sở dữ liệu thường xuyên?

Không, chắc chắn không bình thường khi có khóa cơ sở dữ liệu không thường xuyên. Từ đọc câu chuyện của bạn, bạn nói rằng bạn có cả dịch vụ và nhà cung cấp nội dung kéo từ cơ sở dữ liệu, vì vậy có thể bạn đang khóa cơ sở dữ liệu giữa hai lần truy cập.

Điều tôi thường làm là đảm bảo rằng tôi xử lý tất cả quyền truy cập cơ sở dữ liệu của mình thông qua nhà cung cấp nội dung. Bằng cách có một điểm vào cơ sở dữ liệu, bạn có thể đảm bảo rằng mọi thành phần phần mềm đều sử dụng cùng một logic để truy cập DB. Bạn có thể truy cập dịch vụ của mình qua DB thông qua nhà cung cấp nội dung không?

Bạn cũng nên nhớ rằng bằng cách đặt DB của bạn phía sau nhà cung cấp nội dung, nó vẫn có thể được truy cập bởi nhiều luồng cùng một lúc. Để đảm bảo rằng bạn đang truy cập DB chỉ một luồng tại một thời điểm bạn có thể đặt các cấu trúc đồng bộ trên DB bên trong nhà cung cấp nội dung của bạn. Rõ ràng nếu bạn đang làm rất nhiều viết dài/đọc cho DB, khóa trong thời trang này sẽ hoàn toàn phá hủy ứng dụng của bạn. Việc đặt tất cả mã DB của bạn vào bên trong nhà cung cấp nội dung cũng sẽ cung cấp cho bạn một điểm gỡ lỗi duy nhất sẽ giúp bạn tìm ra nếu có nhiều luồng truy cập DB.

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