database is locked和SQLITE_BUSY

下面我做了几个实验:

1、多个线程(pthread),使用同一个句柄(一次sqlite3_open,同一个数据库文件),在多个线程中同时使用此句柄,这些线程中有的是进行select操作的,有的是进行update操作的,使用的都是sqlite3_exec函数;结果是没有发现database is locked错误;

程序源码(mutitrhead.c ):

 

  1. #include <sqlite3.h>  
  2. #include <stdio.h>  
  3. #include <pthread.h>  
  4. #include <string.h>  
  5. #include "main.h"  
  6.   
  7. #ifdef _WIN32  
  8. #include <windows.h>  
  9. #define sleep(x) Sleep((x)*1000)  
  10. #else  
  11. #define sleep(x) sleep(x)  
  12. #endif  
  13.   
  14. #define CREATE_SQL      \  
  15.         "CREATE TABLE IF NOT EXISTS \"mutiprocess\" ("              \  
  16.         "\"id\"  INTEGER NOT NULL PRIMARY KEY,"       \  
  17.         "\"src\"  TEXT(1024),"                   \  
  18.         "\"videotype\"  INTEGER NOT NULL,"              \  
  19.         "\"postfiledir\"  TEXT(1024)"                   \  
  20.         ");"  
  21. #define REPLACE_SQL "REPLACE INTO mutiprocess (id,src,videotype,postfiledir) VALUES(NULL,%d,%d,%d)"  
  22. #define UPDATE_SQL "UPDATE mutiprocess SET videotype = '2' WHERE id = 1"  
  23. #define SELECT_SQL "SELECT * FROM mutiprocess"  
  24.   
  25. static void* select_cf(void *param)  
  26. {  
  27.         int rc = -1;  
  28.         sqlite3 *db = (sqlite3*)param;  
  29.         char *szErrMsg;  
  30.         pthread_t tid;  
  31.   
  32.         tid = pthread_self();  
  33.         while(1){  
  34.                 rc = sqlite3_exec(db ,SELECT_SQL, 0, 0, &szErrMsg);  
  35.                 if (rc != SQLITE_OK) {  
  36.                         printf("tid %u -- select error.[%s] -- rc=[%d]\n", tid, szErrMsg, rc);  
  37.                         if(strstr(szErrMsg, "database is locked")){  
  38.                                 printf("<database is locked> when executing [%s], retry after 1 second.\n", SELECT_SQL);  
  39.                         }  
  40.                 }else{  
  41.                         printf("tid %u -- successfully execute [%s].\n", tid, SELECT_SQL);  
  42.                 }  
  43.                 sleep(1);  
  44.         }  
  45. }  
  46.   
  47. static void* update_cf(void *param)  
  48. {  
  49.         int rc = -1;  
  50.         sqlite3 *db = (sqlite3*)param;  
  51.         char *szErrMsg;  
  52.         pthread_t tid;  
  53.   
  54.         tid = pthread_self();  
  55.         while(1){  
  56.                 rc = sqlite3_exec(db ,UPDATE_SQL, 0, 0, &szErrMsg);  
  57.                 if (rc != SQLITE_OK) {  重生之大文豪www.dwhao.com
  58.                         printf("tid %u -- update error.[%s] -- rc=[%d]\n", tid, szErrMsg, rc);  
  59.                         if(strstr(szErrMsg, "database is locked")){  
  60.                                 printf("<database is locked> when executing [%s], retry after 1 second.\n", UPDATE_SQL);  
  61.                         }  
  62.                 }else{  
  63.                         printf("tid %u -- successfully execute [%s].\n", tid, UPDATE_SQL);  
  64.                 }  
  65.                 sleep(1);  
  66.         }  
  67. }  
  68.   
  69. int main()  
  70. {  
  71.         pthread_t pid[20];  
  72.         int rc;  
  73.         sqlite3 *db = 0;  
  74.         char *szErrMsg;  
  75.         int i = 0;  
  76.         char sql[1024] = {0};  
  77.   
  78.         rc = sqlite3_open("mutiprocess.db", &db);  
  79.         if (rc != SQLITE_OK) {  
  80.                 printf("open sqlite3 error.\n");  
  81.         }  
  82.   
  83.         rc = sqlite3_exec(db ,CREATE_SQL, 0, 0, &szErrMsg);  
  84.         if (rc != SQLITE_OK) {  
  85.                 printf("create db error-[%s]\n", szErrMsg);  
  86.         }  
  87.   
  88.         for(i = 0; i < 4; i++){  
  89.                 sprintf(sql, REPLACE_SQL, i, i, i);  
  90.                 rc = sqlite3_exec(db ,sql, 0, 0, &szErrMsg);  
  91.                 if (rc != SQLITE_OK) {  
  92.                         printf("replace db error-[%s]\n", szErrMsg);  
  93.                 }  
  94.         }  
  95.   
  96.         for(i = 0; i < 10; i++){  
  97.                 pthread_create(&(pid[i]), 0, select_cf, db);  
  98.                 pthread_detach(pid[i]);  
  99.         }  
  100.         for(; i < 20; i++){  
  101.                 pthread_create(&(pid[i]), 0, update_cf, db);  
  102.                 pthread_detach(pid[i]);  
  103.         }  
  104.   
  105.         while(1){  
  106.                 sleep(-1);  
  107.         }  
  108.         return 0;  
  109. }  


编译:gcc -o mutitrhead mutitrhead.c -lsqlite3 -lpthread

 

运行:./mutithread

注意:只运行这一个进程没有发现任何database is locked的错误提示;如果在运行一个./mutithread进程,那么两个进程都会出现database is locked错误;如果kill掉其中一个进程,那么另外一个不再出现database is locked;

注意两个进程和一个进程的区别,一个是进程数不同,一个是使用的数据库句柄连接不同;上述程序虽然在一个进程中使用了多线程,但是多个线程都是使用了同一个数据库连接(使用一个sqlite3_open返回的句柄),不好区分是什么问题(其实官方网站有一句话很重要『SQLITE_BUSY means that another database connection (probably in another process) is using the database in a way that prevents 茶叶www.aichar.com  you from using it』);这其实已经说明了产生database is locked的原因了,就是出在多个连接上,那么我们在做下面的实验;

2、同一个进程,启动多个线程,每个线程中都打开一个连接(connection,使用一个sqlite3_open返回的句柄),并且在其中做select或者update的操作;结果会出现database is locked错误;

程序源码(muticonnection.c):

 

  1. #include <sqlite3.h>  
  2. #include <stdio.h>  
  3. #include <pthread.h>  
  4. #include <string.h>  
  5. #include "main.h"  
  6.   
  7. #ifdef _WIN32  
  8. #include <windows.h>  
  9. #define sleep(x) Sleep((x)*1000)  
  10. #else  
  11. #define sleep(x) sleep(x)  
  12. #endif  
  13.   
  14. #define CREATE_SQL      \  
  15.         "CREATE TABLE IF NOT EXISTS \"mutiprocess\" ("              \  
  16.         "\"id\"  INTEGER NOT NULL PRIMARY KEY,"       \  
  17.         "\"src\"  TEXT(1024),"                   \  
  18.         "\"videotype\"  INTEGER NOT NULL,"              \  
  19.         "\"postfiledir\"  TEXT(1024)"                   \  
  20.         ");"  
  21. #define REPLACE_SQL "REPLACE INTO mutiprocess (id,src,videotype,postfiledir) VALUES(NULL,%d,%d,%d)"  
  22. #define UPDATE_SQL "UPDATE mutiprocess SET videotype = '2' WHERE id = 1"  
  23. #define SELECT_SQL "SELECT * FROM mutiprocess"  
  24.   
  25. static void* select_cf(void *param)  
  26. {  
  27.         int rc;  
  28.         sqlite3 *db = 0;  
  29.         char *szErrMsg;  
  30.         int i = 0;  
  31.         char sql[1024] = {0};  
  32.         pthread_t tid;  
  33.   
  34.         rc = sqlite3_open("mutiprocess.db", &db);  
  35.         if (rc != SQLITE_OK) {  
  36.                 printf("open sqlite3 error.\n");  
  37.         }  
  38.   
  39.         rc = sqlite3_exec(db ,CREATE_SQL, 0, 0, &szErrMsg);  
  40.         if (rc != SQLITE_OK) {  
  41.                 printf("create db error-[%s]\n", szErrMsg);  
  42.         }  
  43.   
  44.         for(i = 0; i < 4; i++){  
  45.                 sprintf(sql, REPLACE_SQL, i, i, i);  
  46.                 rc = sqlite3_exec(db ,sql, 0, 0, &szErrMsg);  
  47.                 if (rc != SQLITE_OK) {  
  48.                         printf("replace db error-[%s]\n", szErrMsg);  
  49.                 }  
  50.         }  
  51.   
  52.         tid = pthread_self();  
  53.         while(1){  
  54.                 rc = sqlite3_exec(db ,SELECT_SQL, 0, 0, &szErrMsg);  
  55.                 if (rc != SQLITE_OK) {  
  56.                         printf("tid %u -- select error.[%s] -- rc=[%d]\n", tid, szErrMsg, rc);  
  57.                         if(strstr(szErrMsg, "database is locked")){  
  58.                                 printf("<database is locked> when executing [%s], retry after 1 second.\n", SELECT_SQL);  
  59.                         }  
  60.                 }else{  
  61.                         printf("tid %u -- successfully execute [%s].\n", tid, SELECT_SQL);  
  62.                 }  
  63.                 sleep(1);  
  64.         }  
  65. }  
  66.   
  67. static void* update_cf(void *param)  
  68. {  
  69.         int rc;  
  70.         sqlite3 *db = 0;  
  71.         char *szErrMsg;  
  72.         int i = 0;  
  73.         char sql[1024] = {0};  
  74.         pthread_t tid;  
  75.   
  76.         rc = sqlite3_open("mutiprocess.db", &db);  
  77.         if (rc != SQLITE_OK) {  
  78.                 printf("open sqlite3 error.\n");  
  79.         }  
  80.   
  81.         rc = sqlite3_exec(db ,CREATE_SQL, 0, 0, &szErrMsg);  
  82.         if (rc != SQLITE_OK) {  
  83.                 printf("create db error-[%s]\n", szErrMsg);  
  84.         }  
  85.   
  86.         for(i = 0; i < 4; i++){  
  87.                 sprintf(sql, REPLACE_SQL, i, i, i);  
  88.                 rc = sqlite3_exec(db ,sql, 0, 0, &szErrMsg);  
  89.                 if (rc != SQLITE_OK) {  
  90.                         printf("replace db error-[%s]\n", szErrMsg);  
  91.                 }  
  92.         }  
  93.   
  94.         tid = pthread_self();  
  95.         while(1){  
  96.                 rc = sqlite3_exec(db ,UPDATE_SQL, 0, 0, &szErrMsg);  
  97.                 if (rc != SQLITE_OK) {  
  98.                         printf("tid %u -- update error.[%s] -- rc=[%d]\n", tid, szErrMsg, rc);  
  99.                         if(strstr(szErrMsg, "database is locked")){  
  100.                                 printf("<database is locked> when executing [%s], retry after 1 second.\n", UPDATE_SQL);  
  101.                         }  
  102.                 }else{  
  103.                         printf("tid %u -- successfully execute [%s].\n", tid, UPDATE_SQL);  
  104.                 }  
  105.                 sleep(1);  
  106.         }  
  107. }  
  108.   
  109. int main()  
  110. {  
  111.         pthread_t pid[20];  
  112.         int i = 0;  
  113.   
  114.         for(i = 0; i < 10; i++){  
  115.                 pthread_create(&(pid[i]), 0, select_cf, 0);  
  116.                 pthread_detach(pid[i]);  
  117.         }  
  118.         for(; i < 20; i++){  
  119.                 pthread_create(&(pid[i]), 0, update_cf, 0);  
  120.                 pthread_detach(pid[i]);  
  121.         }  
  122.   
  123.         while(1){  
  124.                 sleep(-1);  
  125.         }  
  126.         return 0;  
  127. }  


编译:gcc -o muticonnection muticonnection.c -lsqlite3 -lpthread

 

运行:./muticonnection

 

总结:看来出现这个错误是因为多数是因为使用了多个连接(多个sqlite3_open返回的句柄)导致的,这里我的说法是“多数”,因为还有别的原因,请见官方网站的解释

还有一点要注意:

database is locked是SQLITE_BUSY的错误,不要和SQLITE_LOCKED混淆;

SQLITE_LOCKED(6) means the source of contention is internal and comes from the same database connection that received the SQLITE_LOCKED error.

SQLITE_BUSY(5) means that another database connection (probably in another process) is using the database in a way that prevents you from using it.

posted @ 2014-01-22 17:35  将夜  阅读(1910)  评论(0编辑  收藏  举报