[英]Managing sqlite database in a multithreaded environment
使用sqlite C ++库时,可以使用sqlite3_open_v2
打开数据库。 这将产生数据库的句柄,并将设置指向该句柄的指针。
使用该指针,我可以调用sqlite3_prepare_v2
来准备sqlite语句,然后可以使用sqlite3_step
逐步查询结果。
现在,我正在一个有多个连续创建和销毁多个线程的环境中工作(这是一个服务器应用程序,它产生新的线程来服务传入的(可能是并发的)连接。 现在,据我所知,我应该在每次创建新线程时通过调用sqlite3_open_v2
来创建同一数据库的新句柄。 但是,这会增加大量的计算开销,因为创建数据库的新连接可能要花一些时间,并且我需要处理很多连接。
所以我想知道是否有更有效的方法来实现这一目标。 例如,是否有一种方法可以使所有内容互斥以解决我的问题? 我可以将对我仅有的连接对象的调用互斥:这将与数据库的通信序列化。
这行得通吗? 还是有一个原因,即使我避免任何形式的并发,也不能使用来自多个不同线程的同一连接对象?
如果这可以工作,我应该只是我的序列化调用sqlite3_prepare_v2
,还是我第一次调用sqlite3_step
,还是我的所有来电sqlite3_step
? 我的意思是:第一次调用step
时,每次调用step
时都会加载所有结果或与实际的数据库文件进行通信?
所不同的是mutexing只调用之间的prepare
,直到我已经完成锁定一切step
通过结果平。
这样的事情可行吗?我应该只是每次都创建与数据库的新连接并让sqlite处理所有并发性吗?或者我错过了一些可以轻松解决问题的重要内容?
您可以让sqlite3为您处理所有这些,默认情况下应该如此。 sqlite3库默认情况下应使用SQLITE_THREADSAFE=1
(强调我的):
SQLITE_THREADSAFE = <0或1或2>
此选项控制代码是否包含在SQLite中以使其能够在多线程环境中安全运行。 默认值为SQLITE_THREADSAFE = 1 ,可以在多线程环境中安全使用。
默认情况下,也应使用 SQL_CONFIG_SERIALIZED
(强调我的意思):
SQLITE_CONFIG_SERIALIZED
此选项没有参数。 此选项将线程处理模式设置为序列化。 换句话说,此选项启用所有互斥锁,包括数据库连接和准备好的语句对象上的递归互斥锁。 在这种模式下(这是使用SQLITE_THREADSAFE = 1编译SQLite时的默认设置) ,SQLite库本身将序列化对数据库连接和预准备语句的访问,以便应用程序可以在不同线程中自由使用相同的数据库连接或相同的预准备语句与此同时。
但是,您也可以在初始化之前通过调用sqlite3_config
自己更改它:
sqlite3_config(SQL_CONFIG_SERIALIZED);
然后,您应该能够使用SQLITE_OPEN_FULLMUTEX
打开数据库 :
sqlite3* pDatabase;
sqlite3_open_v2("MyDatabase.db", &pDatabase, SQLITE_OPEN_FULLMUTEX, nullptr);
您还可以使用std::mutex
防止访问sqlite3调用,但这不是必需的,因为sqlite3为您处理了它(但是如果由于某些原因由于某些原因您以不同的方式构建库,那么这将是可行的)。
我认为您应该检查在sqlite3_initialize()
之后是否调用sqlite3_config()
函数。 如果这样,函数sqlite3_config()
返回SQLITE_MISUSE。
这是有关与错误代码SQLITE_MISUSE有关的sqlite3-config()API的部分解释。
sqlite3_config()
接口只能在使用sqlite3_initialize()进行库初始化之前或在通过sqlite3_shutdown()关闭后调用。 如果sqlite3_config()
被称为后sqlite3_initialize()
和前sqlite3_shutdown()
然后将返回SQLITE_MISUSE。 但是请注意,可以将sqlite3_config()
作为应用程序定义的sqlite3_os_init()的实现的一部分来调用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.