2011-04-25 37 views
7

Tôi đang sử dụng wrapper FMDatabase SQLite trong Objective C và tôi có vấn đề sau:Cơ sở dữ liệu SQLite với FMDatabase Wrapper

Tôi đang chạy một phân tích cú pháp XML và DB chèn trong một thread nền cho một số nội dung mà người dùng không có thể truy cập, tuy nhiên người dùng có thể tương tác với một giao diện người dùng và cơ sở dữ liệu từ phần họ đang ở.

The FMDatabase <FMDatabase: 0x17b7b0> is currently in use. 

ngẫu nhiên, tôi sẽ nhận được một "FMDatabase đã được sử dụng" thông báo và mảng sẽ không bao giờ có dân cư bởi cơ sở dữ liệu. Tôi đã theo ấn tượng rằng lớp FMDatabase sẽ xử lý các truy vấn một khi nó trở thành tự do, nhưng tôi có một:

while(contents.count < 1){ 
    sleep(1); 
} 

Hy vọng rằng một khi cơ sở dữ liệu giải phóng, mảng sẽ được áp dụng. Tôi cũng đã cố gắng chạy lại tập lệnh dân số mảng nếu DB đang bận nhưng không có kết quả.

Xin lỗi nếu câu hỏi này gây nhầm lẫn, tôi rất vui được làm rõ.

Trả lời

7

Tôi gặp phải sự cố tương tự.

Tôi đã chuyển sang FMDatabaseQueue cho mỗi truy vấn/cập nhật cơ sở dữ liệu tôi phải làm. Nó hoạt động như một say mê !

Sử dụng performSelectorOnMainThread là một ý tưởng hay nhưng khi nói đến mã hóa thực tế, có thể khá phức tạp khi chuyển đối số của bạn và nhận kết quả để sử dụng tiếp.

EDIT: đây là một ví dụ nhỏ

-(void) updateTaskStateAsync:(NSNumber *)taskID withNewStatus:(NSNumber *)state andCompletionBlock:(void(^)(BOOL status))completionBlock{ 

    NSString *errInfo = [NSString stringWithFormat:@"taskID %d - state %d", [taskID intValue], [state intValue]]; 

    [queue inDatabase:^(FMDatabase *db) { 
     BOOL r = [db executeUpdate:@"UPDATE tasks SET state=?, date_job_last_updated=? WHERE identifier=?", state, [NSDate dateWithTimeIntervalSinceNow:0], taskID]; 
     DB_DISPLAY_ERROR(errInfo); // convenient macro to log errors 

     if(completionBlock) 
      completionBlock(r); 
    }]; 
} 

-(BOOL) updateTaskStateSync:(NSNumber *)taskID withNewStatus:(NSNumber *)state { 

    NSString *errInfo = [NSString stringWithFormat:@"taskID %d - state %d", [taskID intValue], [state intValue]]; 
    __block BOOL r = NO; 
    __block BOOL ended = NO; 

    [queue inDatabase:^(FMDatabase *db) { 
     r = [db executeUpdate:@"UPDATE tasks SET state=?, date_job_last_updated=? WHERE identifier=?", state, [NSDate dateWithTimeIntervalSinceNow:0], taskID]; 
     DB_DISPLAY_ERROR(errInfo); // convenient macro to log errors 

     ended = YES; 
    }]; 

    NSCondition *cond = [[NSCondition alloc] init]; 
    [cond lock]; 
    while(!ended) 
     [cond wait]; 

    [cond unlock]; 

    return r; 
} 
+0

tôi muốn làm giống như bạn, nhưng đối với truy vấn trong FMDatabaseQueue, kết quả phải trở lại async ..... nó không phải là rất thuận tiện. Bạn có gợi ý nào không? – flypig

+0

Tôi donnot có vấn đề thực sự. Tôi đã chỉnh sửa câu trả lời của mình để thêm một đoạn mã, vui lòng đính kèm nếu nó không trợ giúp. – dvkch

+0

mã khối được thực hiện bởi hàng đợi fmdb không đồng bộ, và r sẽ được cập nhật trong khối khi mã khối được thực hiện, nhưng bạn chỉ cần trả về r trong dòng cuối cùng của thủ tục .... tôi nghĩ bạn sẽ bị trống đôi khi kết quả truy vấn, tùy thuộc vào trạng thái hàng đợi fmdb. Điều này khiến tôi bối rối trong một vài ngày .. có thể là chúng ta nên chuyển một khối hoàn thành để trả lại kết quả truy vấn, ví dụ: "(BOOL) updateTaskState: (NSNumber *) taskID vớiNewStatus: (NSNumber *) trạng thái hoàn thành: (void (^) (BOOL r)) hoàn thành;" và gọi hoàn thành (r) trong [queue inDatabase:^(FMDatabase * db) {..}] chặn. – flypig

4

Bạn đang gặp vấn đề này vì ứng dụng của bạn đa luồng và bạn đang truy cập cùng một cơ sở dữ liệu FMDatabase từ các luồng khác nhau. Một câu hỏi tương tự, nhưng đối với Python, có thể được tìm thấy here.

FMDatabase là trình bao bọc xung quanh API sqlite. sqlite theo mặc định không cho phép đồng thời, do đó, FMDatabase sử dụng biến thành viên, được gọi là "inUse", để theo dõi. Để khắc phục sự cố của bạn, hãy thử một trong các phương pháp này được xác định trên NSObject để tất cả các cuộc gọi đến FMDatabase xảy ra trên cùng một chuỗi.

  • performSelectorOnMainThread: withObject: waitUntilDone:
  • performSelectorOnMainThread: withObject: waitUntilDone: chế độ:
  • performSelector: onThread: withObject: waitUntilDone:
  • performSelector: onThread: withObject: waitUntilDone: chế độ:
Các vấn đề liên quan