這兩天在項(xiàng)目中用大強(qiáng)度大頻率的方法測試時(shí)遇到sqlite報(bào)database is locked的問題,
分析下來原因是sqlite對數(shù)據(jù)庫做修改操作時(shí)會(huì)做(文件)鎖使得其它進(jìn)程同一時(shí)間使用時(shí)會(huì)報(bào)該錯(cuò)誤(也就是SQLITE_BUSY),,但如果僅是多進(jìn)程或多線程查詢sqlite是支持的,。
解決方法有:
1,。使用進(jìn)程或線程間的同步機(jī)制以避免同時(shí)操作,;如用信號(hào)量,互斥鎖等(pthread_mutex_lock,,pthread_mutex_unlock),如果你的項(xiàng)目工程較大要求較高的話建議用此方法自行封裝函數(shù)處理同步
2,。使用sqlite提供的兩個(gè)busy handler函數(shù),但對于一個(gè)連接來說,,只能有一個(gè)busy handle,,兩個(gè)函數(shù)會(huì)相互影響,設(shè)置一個(gè)的同時(shí)會(huì)清除另一個(gè),,應(yīng)根據(jù)需要來選擇,。
int sqlite3_busy_handler(sqlite3 *, int (*)(void *, int), void *)
不注冊此函數(shù)時(shí)默認(rèn)回調(diào)函數(shù)為NULL,清除busy handle,,申請不到鎖直接返回;
函數(shù)可以定義一個(gè)回調(diào)函數(shù),當(dāng)出現(xiàn)數(shù)據(jù)庫忙時(shí)sqlite會(huì)調(diào)用該函數(shù)進(jìn)行延時(shí)并返回非0會(huì)重試本次操作,回調(diào)函數(shù)的第二個(gè)參數(shù)會(huì)被傳遞為此次因BUSY忙事件而調(diào)用該函數(shù)的次數(shù),因此你完全可以自行控制多少次后(也就是延時(shí)多少后)才真正返回BUSY;
回調(diào)函數(shù)返回非0,數(shù)據(jù)庫會(huì)重試當(dāng)前操作,,返回0則當(dāng)前操作返回SQLITE_BUSY;
int sqlite3_busy_timeout(sqlite3*, int ms);
不注冊此函數(shù)時(shí)默認(rèn)超時(shí)等待為0,,當(dāng)ms<=0時(shí),清除busy handle,,申請不到鎖直接返回;
定義一個(gè)毫秒數(shù),,當(dāng)未到達(dá)該毫秒數(shù)時(shí),sqlite會(huì)sleep并重試當(dāng)前操作,
如果超過ms毫秒,,仍然申請不到需要的鎖,,當(dāng)前操作返回SQLITE_BUSY;
很多人用這個(gè)函數(shù)沒有成功,其實(shí)只要你仔細(xì)查看sqlite的源碼就會(huì)發(fā)現(xiàn),,
這個(gè)函數(shù)實(shí)際上注冊了一個(gè)默認(rèn)的sqlite3_busy_handler(sqliteDefaultBusyCallback),,而這個(gè)回調(diào)函數(shù)在你的編譯環(huán)境下可能使得第二個(gè)ms參數(shù)必需要大于1000且是他的整數(shù)倍才有意義,由于此默認(rèn)callback函數(shù)延時(shí)較大,建議自己寫回調(diào)函數(shù)然后用slite3_busy_handler注冊,這樣就可以自己用自己的延時(shí)函數(shù)或方法進(jìn)行處理了.
附:===================================================================
static int sqliteDefaultBusyCallback(
void *ptr, /* Database connection */
int count /* Number of times table has been busy */
)
{
#if SQLITE_OS_WIN || (defined(HAVE_USLEEP) && HAVE_USLEEP)
static const u8 delays[] =
{ 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 };
static const u8 totals[] =
{ 0, 1, 3, 8, 18, 33, 53, 78, 103, 128, 178, 228 };
# define NDELAY (sizeof(delays)/sizeof(delays[0]))
sqlite3 *db = (sqlite3 *)ptr;
int timeout = db->busyTimeout;
int delay, prior;
assert( count>=0 );
if( count < NDELAY ){
delay = delays[count];
prior = totals[count];
}else{
delay = delays[NDELAY-1];
prior = totals[NDELAY-1] + delay*(count-(NDELAY-1));
}
if( prior + delay > timeout ){
delay = timeout - prior;
if( delay<=0 ) return 0;
}
sqlite3OsSleep(db->pVfs, delay*1000);
return 1;
#else
sqlite3 *db = (sqlite3 *)ptr;
int timeout = ((sqlite3 *)ptr)->busyTimeout;
if( (count+1)*1000 > timeout ){
return 0;//1000>timeout,so timeout must bigger than 1000
}
sqlite3OsSleep(db->pVfs, 1000000);//1000ms
return 1;
#endif
}
int sqlite3_busy_timeout(sqlite3 *db, int ms){
if( ms>0 ){
db->busyTimeout = ms;
sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db);
}else{
sqlite3_busy_handler(db, 0, 0);
}
return SQLITE_OK;
}
3、解決方法二
加上一個(gè)循環(huán)判斷,。
while( 1 )
{
if( SQLITE_OK != sqlite3_exec( myconn, sql, 0, 0, &m_sqlerr_msg) )
{
if( strstr(m_sqlerr_msg, "database is locked") )
{
sleep(1);
continue;
}
break;
}
}
4,、解決方法三
用信號(hào)量做PV操作
sem_p(semid,0);
sqlite3_exec( myconn, sql, 0, 0, &m_sqlerr_msg),;
sem_v(semid,0);