2012-10-19 36 views
5

Tôi đang sử dụng SQLiteOpenHelper để viết và đọc từ cơ sở dữ liệu SQlite trên Android. Khi người dùng nhấp vào UI tôi đọc từ cơ sở dữ liệu SQLite bằng cách sử dụng AsyncTask nhưng tại thời điểm samo chính xác tôi đang cập nhật và ghi vào cơ sở dữ liệu trong nền bằng cách sử dụng AsyncTask khác.Truy cập đa luồng SQlite Android

Mỗi lần x tôi nhận được ngoại lệ bị khóa cơ sở dữ liệu. Làm thế nào tôi có thể sửa lỗi này? Có thể truy cập SQlite bằng cách nào đó từ nhiều luồng cùng một lúc không?

Tôi đang sử dụng nó như thế: Tôi có một lớp Cơ sở dữ liệu mở rộng từ SQLiteOpenHelper. Tôi thực hiện onCreate và onUpgrade phương pháp và mọi Tôi đọc từ cơ sở dữ liệu hoặc văn bản cho cơ sở dữ liệu tôi sử dụng SQLiteDatabase như thế:

SQLiteDatabase database = null; 
try { 

    database = new Database(context).getWritableDatabase(); 

    .... 
    writing and reading from database... 
    .... 

} catch (Exception e) { 
    e.printStackTrace(); 
} finally { 
    if (database != null) { 
     database.close(); 
    } 
} 

Vào cuối Tôi cũng SQLiteStatements gần gũi và Cursors nếu tôi sử dụng chúng. Tôi có nên sử dụng câu trả lời @Justin và có một singleton của lớp cơ sở dữ liệu trong ứng dụng?

Đây là lỗi tôi nhận được:

E/SqliteDatabaseCpp(17377): sqlite3_open_v2("/data/data/com.skulptur/databases/LGM.s3db", &handle, 6, NULL) failed 
E/SQLiteDatabase(17377): Failed to open the database. closing it. 
E/SQLiteDatabase(17377):  android.database.sqlite.SQLiteDatabaseLockedException: database is locked 
E/SQLiteDatabase(17377): at android.database.sqlite.SQLiteDatabase.dbopen(Native Method) 
E/SQLiteDatabase(17377): at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:983) 
E/SQLiteDatabase(17377): at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:956) 
E/SQLiteDatabase(17377): at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:1021) 
E/SQLiteDatabase(17377): at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:750) 
E/SQLiteDatabase(17377): at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:221) 
E/SQLiteDatabase(17377): at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:149) 
E/SQLiteDatabase(17377): at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:223) 
+0

Tôi nghĩ mọi thứ bạn có thể làm với thư viện android trên sqllite đều được đồng bộ hóa. Bạn không thể thử và bắt ngoại lệ và thử lại nếu bạn nhận được trạng thái khóa? – quinestor

+1

Bạn có thể chỉnh sửa bài đăng của mình và đưa ra vài dòng đầu tiên của ngoại lệ và bất kỳ câu lệnh gây ra nào không? Tôi nghi ngờ điều này là ít hơn về những gì bạn đang làm và nhiều hơn nữa về tái sử dụng một cơ sở dữ liệu đóng cửa hoặc một cái gì đó. – Gray

Trả lời

7

Đây là những gì tôi làm để tránh các vấn đề về khóa .. Tôi cho phép ứng dụng của tôi xử lý một cá thể trợ giúp db của tôi và luôn tham khảo nó để xử lý DB của tôi.

public class MyApp extends Application { 
    // My instance of SQLiteOpenHelper 
    public static DbHelper openHelper; 

    @Override 
    public void onCreate() { 
     super.onCreate(); 
     if (openHelper == null) { 
      openHelper = new DbHelper(this); 
     } 
    } 

    public synchronized static SQLiteDatabase getDB() { 
     return openHelper.getWritableDatabase(); 
    } 
} 

Khi bạn thực hiện việc này, bất cứ khi nào bạn muốn thực hiện truy vấn db, hãy xử lý db như MyApp.getDB() và bạn sẽ không bao giờ gặp vấn đề về khóa. Hãy chắc chắn KHÔNG BAO GIỜ đóng DB mặc dù. Mẫu này duy trì một kết nối duy nhất mọi lúc trong ứng dụng của bạn. SQLite là có nghĩa là để được đồng bộ trên Android vì vậy nếu bạn đã dài tiến trình đang chạy DB, giống như 1000 chèn trong một giao dịch duy nhất bạn sẽ muốn mã hóa nó như thế này:

db.beginTransaction(); 
try { 
    for (DBRow row : insertList) { 
     // your insert code 
     insertRow(row); 
     db.yieldIfContendedSafely(); 
    } 
    db.setTransactionSuccessful(); 
} finally { 
    db.endTransaction(); 
} 

này sẽ cho phép truy vấn khác xen vào bản thân để bạn không thấy ứng dụng của mình bị tạm dừng trong khi cập nhật nền.

+2

bạn có thể làm cho 'SQLiteOpenHelper' của bạn trở thành một singleton tốt hơn so với lớp' Application'. – kdehairy

+0

vâng, tôi nhận ra rằng sau khi viết điều này: - \ ... không cảm thấy như thay đổi câu trả lời của tôi – JustinMorris

+6

Tôi sợ bạn sai về giả định của bạn không bao giờ gặp vấn đề về khóa: Điều duy nhất bạn đang đồng bộ hóa là quyền truy cập của bạn với phương thức 'getWritableDatabase', nghĩa là: chỉ * this * sẽ không bao giờ được gọi đồng thời, điều gì sẽ xảy ra với đối tượng' SQLiteDatabase' mà nó trả về, là * không đồng bộ *. – theV0ID

1

Có vài điều để thử. Lần thử đầu tiên chuyển cùng một phiên bản SQLiteOpenHelper cho mọi tác vụ của bạn. Thứ hai đang sử dụng beginTransaction và endTransaction trên SQLiteDatabase bên trong Trình trợ giúp của bạn. Thứ ba là thêm synchronized vào tất cả các trợ giúp của bạn được sử dụng trong các nhiệm vụ.

+0

cách của bạn là tốt, nhưng tôi thích ContentProvider, nó mang lại cho tôi sự tách biệt giữa ứng dụng và db. Bạn cũng có thể xem xét ORMLite hoặc một ORM giống như lib, có nhiều người trong số họ, ví dụ tốt là CROM những gì tôi đã làm một số thời gian trước đây https: // github.com/rysiekblah/crom –

0

Tôi nghĩ bạn đang sử dụng kết nối cơ sở dữ liệu không chính xác. Nó có thể được gây ra bởi con trỏ không rõ ràng hoặc smth khác. Sqlite cơ sở dữ liệu thực hiện là thread an toàn và có thể được truy cập đồng thời từ các chủ đề khác nhau. Vui lòng cung cấp thêm chi tiết về vấn đề của bạn (theo dõi ngăn xếp ngoại lệ, mẫu mã gây ra ngoại lệ, v.v.) để chúng tôi có thể giúp bạn.

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