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, 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{13-11-27 sqlite遇到database is locked问题的完美解决
www.360doc.com/content/10/1214/12/87000_77984300.shtml 2/2
sqlite3_busy_handler(db, 0, 0);
}
return SQLITE_OK;
}
3、解决方法二
加上一个循环判断。
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、解决方法三
用信号量做PV操作
sem_p(semid,0);
sqlite3_exec( myconn, sql, 0, 0, &m_sqlerr_msg);
sem_v(semid,0);

 

http://www.360doc.com/content/10/1214/12/87000_77984300.shtml

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 当出现"sqlite database is locked"的错误时,意味着有其他进程或线程正在访问或修改数据库文件,并且已经对其进行了独占锁定。SQLite数据库使用一种称为独占性写入锁(exclusive write lock)的算法来处理并发访问。 造成数据库被锁定的常见情况有以下几种: 1. 在一个连接同时启动多个事务并尝试修改数据库SQLite数据库一次只能有一个写入事务,其他事务必须等待直到当前事务完成。 2. 在一个连接同时启动多个写操作(如插入、更新或删除)线程,并尝试同时修改数据库。 3. 一个事务在长时间运行(例如,处理大量数据)而没有释放锁定,导致其他连接无法获取锁定。 为解决"sqlite database is locked"错误,可以采取以下几种方法: 1. 确保在一个连接只有一个事务在操作数据库:在一个事务执行完毕前,不要同时启动其他事务。 2. 在使用写操作之前,检查数据库是否已经被锁定。可以使用SQLite的函数`sqlite3_busy_timeout()`来设置等待锁定的超时时间,以避免长时间阻塞。 3. 优化事务操作:将事务分解为多个较小的事务,或者使用批量插入、更新和删除操作来减少每个操作的次数。 4. 如果可能的话,通过使用缓存机制或调整读写操作的时间,尽量减少数据库的并发读写操作。 最后,需要注意的是,使用SQLite时要正确处理并发访问以及锁定,以保证数据库的一致性和可用性。 ### 回答2: "sqlite database is locked" 是SQLite数据库的一个错误信息,表示当前的数据库文件被其他进程锁定,无法执行请求的操作。 当多个进程或线程同时访问同一个SQLite数据库文件时,会出现锁定现象。这是为了确保数据的完整性和一致性,避免多个进程同时修改数据库而导致冲突和损坏。 出现"sqlite database is locked"错误的情况有以下几个可能原因: 1. 并发访问:如果多个进程或线程同时试图访问数据库,其一个进程可能会独占数据库文件资源,而其他进程则被阻塞并显示此错误。 2. 锁定问题:一个进程已经开始了一个事务并锁定了数据库文件,而另一个进程尝试访问相同的数据库文件,发生冲突。 3. 操作冲突:当一个进程正在执行一个写操作时,另一个进程也尝试执行写操作,会产生冲突。SQLite不支持并发写操作,因此会产生"sqlite database is locked"错误。 解决这个问题的方法有: 1. 等待:可以通过等待一段时间,让占用数据库资源的进程完成操作,然后再次尝试访问数据库。 2. 优化并发操作:通过合理地规划数据库操作顺序、使用合适的事务管理和锁定机制,以减少并发访问时的冲突机会。 3. 重新设计应用程序:如果并发访问需求较高,可以重新设计应用程序架构,使用数据库服务器或其他分布式数据库解决方案,来更好地支持并发操作。 总之,"sqlite database is locked"错误表示数据库文件被其他进程锁定,我们需要合理规划并发访问,使用合适的解决方法来解决这个问题。 ### 回答3: SQLite数据库被锁是一个常见的错误,通常是由于多个进程或线程同时尝试对同一个数据库进行读写操作而导致的。当一个进程或线程正在执行一个事务并且没有释放锁时,其他进程或线程将无法访问该数据库,从而导致数据库被锁。 解决这个问题的方法有几种: 1. 等待:可以尝试在一段时间内等待数据库锁的释放,然后重试执行操作。这可能需要根据具体情况调整等待时长。 2. 优化访问模式:检查代码的访问模式,并确保每个进程或线程都按照正确的顺序访问数据库,以避免出现冲突。 3. 使用事务:事务可以保证对数据库的原子性操作,最大限度地减少锁定时间。确保在适当的时候开始和提交事务。 4. 关闭连接:在某些情况下,关闭所有尝试访问数据库的连接,并重新打开连接可能有助于解决锁定问题。 总的来说,解决SQLite数据库被锁问题的关键在于识别并处理潜在的并发访问冲突,采取适当的措施以确保线程安全并最大限度地减少对数据库的访问冲突。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值