sqlite3 database is locked解决方案

注意:

sqlite3只支持一写多读.
读与读可以同时进行
读与写不可同时进行
写与写不可同时进行

什么时候会返回SQLITE_BUSY错误码?

官方文档给出的解释是:
The SQLITE_BUSY result code indicates that the database file could not be written (or in some cases read) because of concurrent activity by some other database
connection, usually a database connection in a separate process.
这里所说的 数据库连接 实际上指的是用于sqlite3_open函数的sqlite3* 结构体指针。也就是说,以下两种情况可能会返回SQLITE_BUSY错误码:
1、同一进程内的多个线程将不同的 sqlite3* 指针用于sqlite3_open()函数(即打开同一个数据库,但它们是不同的连接,因为sqlite3* 指针各自不同),并向同一数据库执行写入操作。
2、不同的进程将不同的sqlite3* 指针用于sqlite3_open()函数(即打开同一个数据库,但它们是不同的连接,因为sqlite3* 指针各自不同),并向同一数据库执行写入操作。
而SQLite提供的sqlite3_busy_handler()
API函数则为我们提供了一种处理SQLITE_BUSY错误码的机制。使用方法是在调用sqlite3_open()函数打开一个数据库连接后,调用sqlite3_busy_handler()注册一个数据库超时回调函数。该回调函数的原型必须类似于:

int busy_callback(void* lpVoid,int c)
{
	return nRet;
}

其中第一个参数为调用sqlite3_busy_handler()时传入的第三个参数的副本。
第二个参数为基于相同锁定事件的回调函数的前一次调用次数。例如,当第一次执行某个SQL语句时就
超时了,那么SQLite数据库引擎进入busy_callback回调函数时c为0,即第一次超时。如果第二次尝试还是超时,那
么SQLite数据库引擎进入busy_callback回调函数时c为1,依此类推。
而决定SQLite数据库引擎是否再次尝试执行超时的SQL语句是由回调函数的返回值来指定的。当nRet为非0时,SQLite
数据库引擎会等待获得锁,并再次尝试执行超时的SQL语句,直到执行完成。如果下一次尝试还是失败,并且nRet为
非0值,则SQLite数据库引擎不断重复上述过程,直到最终执行成功为止。(也可以配合使用参数c,设置尝试次数n次后,直接返回0,不再尝试)。
上述方法也叫通过sqlite3给的函数sqlite3_busy_handler来实现了延时(次数的延时)

当然,也可以直接在回调函数里增加延时,如下:

int busy_callback(void* lpVoid,int c)
{
	//如果获取不到锁,等待0.5秒,由于多线程操作,等待时其他线程会释放锁
	usleep(500000);
	return 1;
}
//在sqlite3_exec()操作前,调用sqlite3_busy_handler()注册一个数据库超时回调函数
ret= sqlite3_busy_handler(db,busy_callback,(void*)db);
if (ret != SQLITE_OK)
{
    printf("sqlite3_busy_handler failed:%d\n",ret);
	return NULL;
}
// 检查数据库的完整性
ret = sqlite3_exec(db, "PRAGMA integrity_check;", 0, 0, &szErr);

补充:
当然,除了此方案,网上有一些相关的帖子也可以参考:
sqlite3 database is locked 问题解决方案

相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页