在只读环境中访问sqlite3 db时,我遇到了一些问题.在系统(Linux )上,有一个C++应用程序打开(并保持打开)到db的r/w连接。这个应用程序几乎连续地读写。
然后是一个PHP应用程序,每1秒打开一个只读连接来获取数据。它似乎一点问题也没有。
最后,有一个C应用程序应该打开到同一个db的另一个只读连接,并每隔几秒钟获取一次数据。这个应用程序经常运行在忙误差中。
据我从这个主题的帮助和其他问题中了解到的,这通常是在您尝试编写并且有另一个正在运行的事务时触发的。帮助也说“或在某些情况下阅读”,但我不知道这些案例是什么。
在C++应用程序仍在写入时尝试读取可能会发生,但据我所知,这不应导致此错误。读取查询将返回“旧”值,但应该没有问题地完成。
是对的吗?
在这里,返回此错误的C代码:
sqlite3 *db;
sqlite3_stmt *stmt;
char *qry=0;
int rc,value=0;
sqlite3_open_v2( "<mydb>", &db,SQLITE_OPEN_READONLY,NULL);
if (db == NULL)
{
syslog(LOG_INFO,"Failed to open db\n");
return -1;
}
qry=malloc(80);
if (qry) {
sprintf (qry,"select value from dataplc WHERE address=%d",addr);
rc = sqlite3_prepare_v2(db, qry,-1,&stmt,NULL);
if (rc != SQLITE_OK) {
syslog(LOG_INFO, "Failed to read: %d - rc: %d", addr,rc); // -5 -> db busy
value = -1;
} else {
rc = sqlite3_step(stmt);
if (rc == SQLITE_ROW) {
value = sqlite3_column_int(stmt, 0);
// do something
}
}
free (qry);
}
sqlite3_finalize(stmt);
sqlite3_close(db);
return value;在代码或整个方法中有什么明显的错误吗?
发布于 2020-04-08 22:18:20
想必准备需要独占访问来读取数据库的当前架构数据。
一个可能的解决方案是使用sqlite3_busy_handler。
#define ABORT 0
#define CONTINUE 1
int busy_handler(void *data, int attempt) {
printf("attempt: %d\n", attempt);
if(attempt < 10) {
sqlite3_sleep(250);
return CONTINUE;
}
return ABORT;
}在sqlite3_prepare_v2调用之前设置它,如下所示:
sqlite3_busy_handler(db, busy_handler, NULL);重试和睡眠时间的最大数量(以毫秒为单位)应根据您的需求来确定。
正如注释中已经提到的那样,检查sqlite3_open_v2调用的返回代码也是有意义的。
这样使用准备好的语句大概也是有意义的:
rc = sqlite3_prepare_v2(db, "SELECT value FROM dataplc WHERE address = ?1", -1, &stmt, NULL);并将参数绑定到:
sqlite3_bind_int(stmt, 1, addr);如何测试
为了进行测试,可以使用一个技巧,可以在这个很好的答案中找到:https://stackoverflow.com/a/57786662/2331445:
例如,可以简单地将睡眠时间临时设置为1秒(在busy_handler sqlite3_sleep(1000);中)。
然后在准备之前添加一个getchar();。
您的程序只是稍微修改了一下上面提到的点,如下所示:
#include <stdio.h>
#include <sys/syslog.h>
#include "sqlite3.h"
#define ABORT 0
#define CONTINUE 1
int busy_handler(void *data, int attempt) {
printf("attempt: %d\n", attempt);
if (attempt < 10) {
sqlite3_sleep(1000);
return CONTINUE;
}
return ABORT;
}
int read_from_db(int addr) {
sqlite3 *db;
sqlite3_stmt *stmt;
int rc, value = 0;
rc = sqlite3_open_v2("mydb", &db, SQLITE_OPEN_READONLY, NULL);
if (rc != SQLITE_OK) {
sqlite3_close(db);
syslog(LOG_INFO, "Failed to open db\n");
return -1;
}
sqlite3_busy_handler(db, busy_handler, NULL);
printf("press enter to continue:\n");
getchar(); //only for testing
rc = sqlite3_prepare_v2(db, "SELECT value FROM dataplc WHERE address = ?1", -1, &stmt, NULL);
if (rc != SQLITE_OK) {
syslog(LOG_INFO, "Failed to read: %d - rc: %d", addr, rc); // -5 -> db busy
value = -1;
} else {
sqlite3_bind_int(stmt, 1, addr);
rc = sqlite3_step(stmt);
if (rc == SQLITE_ROW) {
value = sqlite3_column_int(stmt, 0);
// do something
}
}
sqlite3_finalize(stmt);
sqlite3_close(db);
return value;
}
int main(void) {
int val = read_from_db(42);
printf("result: %d\n", val);
return 0;
}在sqlite3命令行接口上,可以输入:
begin exclusive;然后,在运行程序的控制台上,您可以按ENTER键。现在它将显示来自busy_handler的printfs。一旦我们用一个
commit;返回结果。

https://stackoverflow.com/questions/61104320
复制相似问题