您的位置:首页 > 数据库

sqlite多进程并发读写模式下,返回SQLITE_BUSY错误的处理方法

2016-06-24 18:38 1631 查看
 SQLite作为一款小型的嵌入式数据库,本身没有提供复杂的锁定机制,无法内部管理多路并发下的数据操作同步问题,更谈不上优化,所以涉及到多路并发的情况,需要外部进行读写锁控制,否则SQLite会返回SQLITE_BUSY错误,以驳回相关请求,这是由于使用当前连接访问数据时,要申请相应级别的锁,而各个级别的锁有些是互斥的,当申请不到锁时就会返回这个错误。这时只要稍等片刻,等其它连接的操作处理完,释放了相斥的锁之后就可以取得锁并进行操作了。

返回SQLITE_BUSY主要有以下几种情况:

1、当有写操作时,其他读操作会被驳回

2、当有写操作时,其他写操作会被驳回

3、当开启事务时,在提交事务之前,其他写操作会被驳回

4、当开启事务时,在提交事务之前,其他事务请求会被驳回

5、当有读操作时,其他写操作会被驳回

6、读操作之间能够并发执行

可采用三种方式处理SQLITE_BUSY

1、用信号量做PV操作

sem_p(semid,0);
sqlite3_exec( myconn, sql, 0, 0, &m_sqlerr_msg);
sem_v(semid,0);

2、自定义一个消息循环处理

int nCount=0;
int nRet=0;
do
{
nRet = sqlite3_exec( m_db , buf , 0 , 0 , &pErrMsg );

if (nRet == SQLITE_BUSY)
{
Sleep(1);
continue;
}
break;
} while (1);

3、采用sqlite3的API函数sqlite3_busy_handler() 或sqlite3_busy_timeout()
sqlite3_busy_handler() 函数当检测到当前连接的数据库处于SQLITE_BUSY状态下,会调用回调函数,在回调函数内可以定义一些行为处理

定义回调函数:

int callback_db(void *ptr,int count)
{
usleep(500000); //如果获取不到锁,等待0.5秒
printf("database is locak now,can not write/read.\n"); //每次执行一次回调函数打印一次该信息
return 1; //回调函数返回值为1,则将不断尝试操作数据库。
} 参数int count为回调函数执行次数,在此处对count值无需要,所以没有进行打印等操作。
<pre name="code" class="cpp">sqlite3_busy_handler(db,callback_db,(void *)db); //一直等待,直到获得锁
sqlite3_exec(db , sqlcmd , NULL, NULL, &zErrMsg );
sqlite3_close(db);


sqlite3_busy_timeout()的实现是在内部调用sqlite3_busy_handler(),并调用sqlite3自己的回调函数sqliteDefaultBusyCallback
SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3 *db, int ms){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
if( ms>0 ){
sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db);
db->busyTimeout = ms;
}else{
sqlite3_busy_handler(db, 0, 0);
}
return SQLITE_OK;
}

在程序中可以在执行数据库命令前调用此函数,第二个参数设置了SQLITE在返回SQLITE_BUSY前需要等待多长的锁清除时间

sqlite3_busy_timeout(db, 30*1000); //最长等待30m
sqlite3_exec(db , sqlcmd , NULL, NULL, &zErrMsg );
sqlite3_close(db);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: