2014-12-09 12 views
6

Vài câu hỏi về sqlite3:sqlite3_prepare_v2/sqlite3_exec

1. Khi cần thiết phải sử dụng phương pháp đầu tiên một và khi người kia? Đó là sự khác biệt giữa chúng?

sqlite3_prepare_v2(_contactDB, sql_stmt_getIdRecepteur, -1, &sqlStatement, NULL); 

if(sqlite3_prepare_v2(_contactDB, sql_stmt_getIdRecepteur, -1, &sqlStatement, NULL) == SQLITE_OK) {} 

2.When được chỉ định nhất để sử dụng 'sqlite3_exec' hơn 'sqlite3_prepare_v2'?

3. Khi cần thiết phải sử dụng đầu tiên, thứ hai hoặc thứ ba:

while(sqlite3_step(sqlStatement) == SQLITE_ROW){} 
if(sqlite3_step(sqlStatement) == SQLITE_ROW){} 
if(sqlite3_step(sqlStatement) == SQLITE_DONE){} 

Cảm ơn bạn trước

Trả lời

9
  1. Bạn luôn phải kiểm tra giá trị trả về của hàm SQLite, để đảm bảo nó thành công, do đó việc sử dụng câu lệnh if được ưu tiên hơn. Và nếu nó thất bại, người ta sẽ gọi sqlite3_errmsg() để lấy một mô tả chuỗi C của lỗi.

  2. Một sẽ sử dụng sqlite3_prepare_v2 (thay vì sqlite3_exec) trong mọi tình huống trong đó một trong hai:

    • ai trở về dữ liệu và do đó sẽ gọi sqlite3_step Tiếp theo một hoặc nhiều sqlite3_column_xxx chức năng, lặp đi lặp lại quá trình cho mỗi hàng dữ liệu; hoặc

    • một giá trị ràng buộc cho các đối tượng giữ chỗ ? trong SQL với sqlite3_bind_xxx.

    Người ta có thể phỏng đoán từ trên chỉ sử dụng sqlite3_exec khi (a) chuỗi SQL không có tham số; và (b) SQL không trả về bất kỳ dữ liệu nào. Các sqlite3_exec là đơn giản, nhưng chỉ nên được sử dụng trong những tình huống cụ thể.

    Xin lưu ý: Điểm liên quan đến phần giữ chỗ ? rất quan trọng: Bạn nên tránh tạo câu lệnh SQL theo cách thủ công (ví dụ: với nội suy chuỗi stringWithFormat hoặc Swift), đặc biệt nếu các giá trị được chèn vào bao gồm đầu vào của người dùng cuối. Ví dụ: nếu bạn gọi số sqlite3_exec bằng câu hỏi INSERT, UPDATE hoặc DELETE đã được tạo bằng cách sử dụng đầu vào của người dùng (ví dụ: chèn một số giá trị do người dùng cung cấp vào cơ sở dữ liệu), bạn có thể gặp phải các vấn đề phát sinh từ dấu ngoặc kép các biểu tượng thoát, v.v. Một cũng được tiếp xúc với các cuộc tấn công SQL injection.

    Ví dụ, nếu commentString được cung cấp như một kết quả của việc người dùng nhập vào, đây sẽ là không khôn ngoan:

    NSString *sql = [NSString stringWithFormat:@"INSERT INTO COMMENTS (COMMENT) VALUES ('%@')", commentString]; 
    if (sqlite3_exec(database, [sql UTF8String], NULL, NULL, NULL) != SQLITE_OK) { 
        NSLog(@"Insert failure: %s", sqlite3_errmsg(database)); 
    } 
    

    Thay vào đó, bạn nên:

    const char *sql = "INSERT INTO COMMENTS (COMMENT) VALUES (?)"; 
    if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) != SQLITE_OK) { 
        NSLog(@"Prepare failure: %s", sqlite3_errmsg(database)); 
    } 
    if (sqlite3_bind_text(statement, 1, [commentString UTF8String], -1, NULL) != SQLITE_OK) { 
        NSLog(@"Bind 1 failure: %s", sqlite3_errmsg(database)); 
    } 
    if (sqlite3_step(statement) != SQLITE_DONE) { 
        NSLog(@"Step failure: %s", sqlite3_errmsg(database)); 
    } 
    sqlite3_finalize(statement); 
    

    Lưu ý, nếu thực hiện đúng này có cảm giác như quá nhiều công việc, bạn có thể sử dụng số FMDB library, điều này sẽ đơn giản hóa nó thành:

    if (![db executeUpdate:@"INSERT INTO COMMENTS (COMMENT) VALUES (?)", commentString]) { 
        NSLog(@"Insert failure: %@", [db lastErrorMessage]); 
    } 
    

    Điều này cung cấp độ cứng của phương pháp sqlite3_prepare_v2, nhưng sự đơn giản của giao diện sqlite3_exec.

  3. Khi lấy nhiều hàng dữ liệu, người ta sẽ sử dụng:

    while(sqlite3_step(sqlStatement) == SQLITE_ROW) { ... } 
    

    Hoặc tốt hơn, nếu bạn muốn làm việc xử lý lỗi thích hợp, bạn sẽ làm:

    int rc; 
    while ((rc = sqlite3_step(sqlStatement)) == SQLITE_ROW) { 
        // process row here 
    } 
    if (rc != SQLITE_DONE) { 
        NSLog(@"Step failure: %s", sqlite3_errmsg(database)); 
    } 
    

    Khi truy xuất một hàng dữ liệu, một sẽ:

    if (sqlite3_step(sqlStatement) != SQLITE_ROW) { 
        NSLog(@"Step failure: %s", sqlite3_errmsg(database)); 
    } 
    

    Khi thực hiện SQL sẽ không trả về bất kỳ dữ liệu, một sẽ:

    if (sqlite3_step(sqlStatement) != SQLITE_DONE) { 
        NSLog(@"Step failure: %s", sqlite3_errmsg(database)); 
    } 
    

Khi sử dụng giao diện SQLite C, bạn có thể thấy rằng phải mất một công việc ít để làm điều đó đúng.Có một wrapper Objective-C mỏng xung quanh giao diện này được gọi là FMDB, không chỉ đơn giản hóa sự tương tác với cơ sở dữ liệu SQLite và mạnh hơn một chút.

+0

Chắc chắn, điều này nên có trong tài liệu! Cảm ơn bạn – Developer3000

+0

BTW, có một chút [giới thiệu trên trang web SQLite.org] (https://www.sqlite.org/cintro.html), mặc dù nó không đi vào chi tiết khi chức năng tiện lợi, 'sqlite3_exec', là thích hợp, và khi nó không phải là. Họ để nó cho bạn để suy ra điều này. Nhưng nó thảo luận về giao diện cơ bản. – Rob

+0

Điều cần biết. Cảm ơn nhiều – Developer3000

1

Đối câu hỏi 1, trong hầu hết trường hợp, bạn cần phải xác minh rằng kết quả bằng SQLITE_OK để đảm bảo lệnh của bạn chạy thành công. (SQLITE_OKint loại **). Do đó, thứ hai được ưu tiên.

Đối câu hỏi 2, hàm sqlite3_exec được sử dụng để chạy bất kỳ lệnh đó không trả lại dữ liệu, bao gồm bản cập nhật, chèn và xóa dần. Lấy dữ liệu từ cơ sở dữ liệu ít liên quan nhiều hơn. Và chức năng sqlite3_prepare_v2 có thể được sử dụng cho SELECT (trong SQL). Thông thường, tạo bảng thường sử dụng bảng đầu tiên.

Đối câu hỏi 3, tốt, khi là dành cho loop, trong khi nếu là dành cho trạng. Nói chung, nếu bạn truy xuất dada từ db, bạn cần một vòng lặp để duyệt qua * mảng trả về **. Nếu bạn chèn dữ liệu vào db (ví dụ), bạn có thể sử dụng SQLITE_DONE để kiểm tra hoạt động của bạn.

Bằng cách này, dữ liệu chính được ưu tiên trong iOS cho hầu hết các trường hợp.

+0

Cảm ơn câu trả lời của bạn. – Developer3000

0

Câu trả lời cuối cho số 2 mà tôi vừa tìm thấy: sử dụng sqlite3_exec (hoặc sử dụng sqlite3_prepare_v2 trong vòng lặp) khi sql_stmt_getIdRecepteur thực sự chứa nhiều câu lệnh SQL. Từ số docs for sqlite3_prepare_v2:

Những thói quen này chỉ biên dịch câu lệnh đầu tiên trong zSql, vì vậy * pzTail chỉ trỏ đến những gì chưa được biên soạn.

sqlite3_exec bao gồm một vòng lặp nội bộ mà các cuộc gọi sqlite3_prepare_v2 nhiều lần cho đến khi toàn bộ chuỗi đầu vào được biên dịch. Nếu bạn không sử dụng sqlite3_exec và bạn có nhiều câu lệnh SQL trong một chuỗi, bạn cần phải kiểm tra giá trị trả về pzTail từ sqlite3_prepare_v2.