QT使用Sqlite多线程注意事项

SQLite支持3种线程模式:
  单线程:这种模式下,没有进行互斥,多线程使用不安全。禁用所有的mutex锁,并发使用时会出错。当SQLite编译时加了SQLITE_THREADSAFE=0参数,或者在初始化SQLite前调用sqlite3_config(SQLITE_CONFIG_SINGLETHREAD)时启用。
  多线程:这种模式下,只要一个数据库连接不被多个线程同时使用就是安全的。源码中是启用bCoreMutex,禁用bFullMutex。实际上就是禁用数据库连接和prepared statement(准备好的语句)上的锁,因此不能在多个线程中并发使用同一个数据库连接或prepared statement。当SQLite编译时加了SQLITE_THREADSAFE=2参数时默认启用。若SQLITE_THREADSAFE不为0,可以在初始化SQLite前,调用sqlite3_config(SQLITE_CONFIG_MULTITHREAD)启用;或者在创建数据库连接时,设置SQLITE_OPEN_NOMUTEX flag。
  串行:sqlite是线程安全的。启用所有的锁,包括bCoreMutex和bFullMutex 。因为数据库连接和prepared statement都已加锁,所以多线程使用这些对象时没法并发,也就变成串行了。当SQLite编译时加了SQLITE_THREADSAFE =1参数时默认启用。若SQLITE_THREADSAFE不为0,可以在初始化SQLite前,调用sqlite3_config(SQLITE_CONFIG_SERIALIZED)启用;或者在创建数据库连接时,设置SQLITE_OPEN_FULLMUTEX flag  。
    而这里所说的初始化是指调用sqlite3_initialize()函数,这个函数在调用sqlite3_open()时会自动调用,且只有第一次调用是有效的.
 
   为了达到线程安全,SQLite在编译时必须将 SQLITE_THREADSAFE 预处理宏置为1。在Windows和Linux上, 已编译的好的二进制发行版中都是这样设置的。 如果不确定你所使用的库是否是线程安全的,可以调用 sqlite3_threadsafe() 接口找出。调用sqlite3_threadsafe()可以获得编译期的SQLITE_THREADSAFE参数 。
 
   也就是说线程模式可以在编译时(通过源码编译sqlite库时)、启动时(使用sqlite的应用程序初始化时)或者运行时(创建数据库连接时)来指定。一般而言,运行时指定的模式将覆盖启动时的指定模式,启动时指定的模式将覆盖编译时指定的模式。但是,单线程模式一旦被指定,将无法被覆盖。默认的线程模式是串行模式。
 
 
编译时选择线程模式
    可以通过定义SQLITE_THREADSAFE宏来指定线程模式。如果没有指定,默认为串行模式。定义宏SQLITE_THREADSAFE=1指定使用串行模式;=0使用单线程模式;=2使用多线程模式。
    sqlite3_threadsafe()函数的返回值可以确定编译时指定的线程模式。如果指定了单线程模式,函数返回false。如果指定了串行或者多线程模式,函数返回true。由于sqlite3_threadsafe()函数要早于多线程模式以及启动时和运行时的模式选择,所以它既不能区别多线程模式和串行模式也不能区别启动时和运行时的模式。
    最后一句可通过sqlite3_threadsafe函数的实现来理解SQLITE_API int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }如果编译时指定了单线程模式,那么临界互斥逻辑在构造时就被省略,因此也就无法在启动时或运行时指定串行模式或多线程模式。
 
启动时选择线程模式
    假如在编译时没有指定单线程模式,就可以在应用程序初始化时使用sqlite3_config()函数修改线程模式。参数SQLITE_CONFIG_SINGLETHREAD可指定为
单线程模式,SQLITE_CONFIG_MULTITHREAD指定为多线程模式,SQLITE_CONFIG_SERIALIZED指定为串行模式。
 
运行时选择线程模式
    如果没有在编译时和启动时指定为单线程模式,那么每个数据库连接在创建时可单独的被指定为多线程模式或者串行模式,但是不能指定为单线程模式。如果在编译时或启动时指定为单线程模式,就无法在创建连接时指定多线程或者串行模式。
    创建连接时用sqlite3_open_v2()函数的第三个参数来指定线程模式。SQLITE_OPEN_NOMUTEX标识创建多线程模式的连接;SQLITE_OPEN_FULLMUTEX标识创建串行模式的连接。如果没有指定标识,或者使用sqlite3_open()或sqlite3_open16()函数来创建数据库连接,那么在编译时或启动时指定的线程模式将作为默认的线程模式使用。

Qt中,使用SQLite多线程可以通过以下步骤实现: 1. 创建SQLite数据库连接:在主线程中创建一个Qt数据库连接对象,并通过`QSqlDatabase::addDatabase("QSQLITE")`方法设置数据库驱动类型为SQLite。然后,使用`QSqlDatabase::setDatabaseName()`方法设置数据库文件的路径。 2. 在每个需要访问数据库线程中,创建独立的数据库连接:对于每个使用SQLite数据库线程,需要在该线程中创建独立的数据库连接。可以通过调用`QSqlDatabase::cloneDatabase()`方法来创建一个与主线程数据库连接相同的副本连接。 3. 在每个线程中执行数据库操作:在每个独立的线程中,使用`QSqlDatabase`对象连接到数据库,并执行相应的数据库操作,如查询、插入、更新或删除。可以使用`QSqlQuery`对象来执行SQL语句。 4. 线程间数据共享:如果多个线程需要共享数据,可以使用Qt提供的线程间通信机制,如信号槽或自定义的全局变量,在不同的线程之间传递数据。 需要注意的是,SQLite数据库多线程访问是线程安全的,可以在多个线程中同时访问同一个数据库。但是,需要注意避免数据库操作的竞争条件,如同时对同一表执行插入和更新操作可能导致数据不一致。 另外,Qt还提供了`QtConcurrent`模块,可以进一步简化多线程编程。该模块提供了一些方便的函数,如`QFuture`和`QFutureWatcher`,可以实现并行执行数据库操作,并在操作完成后通知主线程更新UI等操作。 综上所述,通过上述步骤和Qt提供的多线程编程机制,可以在Qt中实现SQLite数据库多线程访问。注意在并发访问数据库时要处理好线程安全问题,以确保数据的一致性和正确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值