SQLite 是线程安全的,支持多线程操作。如何开启呢?
1, PRAGMA SQLITE_THREADSAFE=2 确保同一个时间只有一个线程操作一个数据库
2,开启WAL模式:原来就是开启了WAL,读写操作都是提交一些事物到WAL文件里面去,然后定时checkpoint提交到数据库,当读取数据的时候,会在wal里面添加一个end mark,这样读取的时候,后面的更新和插入都和读取没关,所以保证了读取同步进行,效率高。
https://blog.csdn.net/zearot/article/details/51039593,但是写写之间还是不能同步的!!!缺点。所以下面这个点
3, SQLite 提供了 Busy Retry 的方案,即发生阻塞时,会触发 Busy Handler,此时可以让线程休眠一段时间后,重新尝试操作。重试一定次数依然失败后,则返回 SQLITE_BUSY 错误码。它是通过文件锁的方式去锁住文件,SQLITE_BUSY 通过 fcntl 进行文件锁,防止其他进程介入。若锁失败,则返回 SQLITE_BUSY。
因为它没有通知的机制,例如其他进程用完这个数据库发出通知,这样SQLite_BUSY 的文件锁就可以成功锁住了文件,所以它才只能通过多次尝试的方法去锁文件
如何对SQLite 进行优化?
1,优化点针对的是上面第3点,由于Busy Retry的机制文件锁没有通知的机制,所以我们可以添加通知的机制:当文件被锁住没办法加文件锁的时候,我们就将我们的事务加到一个FIFO的queue里面,线程通过pthread_cond_wait进入睡眠,当文件解锁的时候,会通过pthread_cond_signal_thread_np 信号去唤醒这个线程,这样线程就可以对这个文件进行锁住去写文件了。
2, 开始MMAP,内存映射,低版本sqllite没有默认打开。但是对WAL还是没有进行MMAP操作,那么怎么办呢?可以减少WAL的删除和重建,在checkpoint之后,修改WAL文件头部的参数,这样SQLite 识别到WAL已经不可用就会重新从头开始写入。 有了上面两个优化就可以大大提升了性能。
3,可以关闭内存统计,内存统计是在全局变量里计算,所以有频繁的加锁解锁操作比较耗时
sqlite3_config(SQLITE_CONFIG_MEMSTATUS, 0)