微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

sqlite遇到database is locked问题的完美解决

sqlite遇到database is locked问题的完美解决


这两天在项目中用大强度大频率的方法测试时遇到sqlite报database is locked的问题,
分析下来原因是sqlite对数据库修改操作时会做(文件)锁使得其它进程同一时间使用时会报该错误(也就是
sqlITE_BUSY),但如果仅是多进程或多线程查询sqlite是支持的。(也有可能是做sql开启事务查询等发生异常,数据库没有关闭,然后再去打开就锁定了)
解决方法有:
1。使用进程或线程间的同步机制以避免同时操作;如用信号量,互斥锁等(pthread_mutex_lock,
pthread_mutex_unlock),如果你的项目工程较大要求较高的话建议用此方法自行封装函数处理同步
2。使用sqlite提供的两个busy handler函数,但对于一个连接来说,只能有一个busy handle,两个函数会相互影响,设
一个的同时会清除另一个,应根据需要来选择。
int sqlite3_busy_handler(sqlite3 *,int (*)(void *,int),void *)
注册函数认回调函数为NULL,清除busy handle,申请不到锁直接返回;
函数可以定义一个回调函数,当出现数据库忙时sqlite会调用函数进行延时并返回非0会重试本次操作,回调函数的第二个
参数会被传递为此次因BUSY忙事件而调用函数次数,因此你完全可以自行控制多少次后(也就是延时多少后)才真正返回
BUSY;
回调函数返回非0,数据库会重试当前操作,返回0则当前操作返回sqlITE_BUSY;
int sqlite3_busy_timeout(sqlite3*,int ms);
注册函数认超时等待为0,当ms<=0时,清除busy handle,申请不到锁直接返回;
定义一个毫秒数,当未到达该毫秒数时,sqlite会sleep并重试当前操作,
如果超过ms毫秒,仍然申请不到需要的锁,当前操作返回sqlITE_BUSY;
很多人用这个函数没有成功,其实只要你仔细查看sqlite的源码就会发现,
这个函数实际上注册一个认的sqlite3_busy_handler(sqliteDefaultBusyCallback),而这个回调函数在你的编译
环境下可能使得第二个ms参数必需要大于1000且是他的整数倍才有意义,由于此认callback函数延时较大,建议自己写回
函数然后用slite3_busy_handler注册,这样就可以自己用自己的延时函数方法进行处理了.
附:===================================================================
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,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{13-11-27 sqlite遇到database is locked问题的完美解决 www.360doc.com/content/10/1214/12/87000_77984300.shtml 2/2 sqlite3_busy_handler(db,0); } return sqlITE_OK; } 3、解决方法加上一个循环判断。 while( 1 ) { if( sqlITE_OK != sqlite3_exec( myconn,sql,&m_sqlerr_msg) ) { if( strstr(m_sqlerr_msg,"database is locked") ) { sleep(1); continue; } break; } } 4、解决方法三 用信号量做PV操作 sem_p(semid,0); sqlite3_exec( myconn,&m_sqlerr_msg); sem_v(semid,0);

原文地址:https://www.jb51.cc/sqlite/199515.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐