如何解决SQLite内存数据库间歇性遇到SQLITE_LOCKED_SHAREDCACHE
我正在使用mybatis 3.4.6和org.xerial:sqlite-jdbc 3.28.0。以下是我的配置,以使用启用了共享模式的内存数据库
db.driver=org.sqlite.JDBC
db.url=jdbc:sqlite:file::memory:?cache=shared
根据test class,db.url
是正确的
尽管我也报告了根据此issue的属性read_uncommitted的错字,但我还是设法在mybatis配置以下设置了正确的事务隔离级别
<environment id="${db.env}">
<transactionManager type="jdbc"/>
<dataSource type="POOLED">
<property name="driver" value="${db.driver}" />
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
<property name="defaultTransactionIsolationLevel" value="1" />
<property name="driver.synchronous" value="OFF" />
<property name="driver.transaction_mode" value="IMMEDIATE"/>
<property name="driver.foreign_keys" value="ON"/>
</dataSource>
</environment>
这行配置
<property name="defaultTransactionIsolationLevel" value="1" />
可以设置正确的 PRAGMA read_uncommitted
值我很确定,因为我调试了用于初始化连接并检查值是否已正确设置的代码
但是,使用上述设置,我的程序在阅读时仍会间歇性地遇到SQLITE_LOCKED_SHAREDCACHE,根据以下屏幕截图中红色矩形突出显示的说明,我认为它不应该发生。我想知道原因和解决方法,尽管发生此错误的可能性很低。
任何想法将不胜感激!
调试配置如下
===CONFINGURATION==============================================
jdbcDriver org.sqlite.JDBC
jdbcUrl jdbc:sqlite:file::memory:?cache=shared
jdbcUsername
jdbcPassword ************
poolMaxActiveConnections 10
poolMaxIdleConnections 5
poolMaxCheckoutTime 20000
poolTimeToWait 20000
poolPingEnabled false
poolPingQuery NO PING QUERY SET
poolPingConnectionsNotUsedFor 0
---STATUS-----------------------------------------------------
activeConnections 5
idleConnections 5
requestCount 27
averageRequestTime 7941
averageCheckoutTime 4437
claimedOverdue 0
averageOverdueCheckoutTime 0
hadToWait 0
averageWaitTime 0
badConnectionCount 0
===============================================================
附件:
下面是例外
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: org.apache.ibatis.transaction.TransactionException: Error configuring AutoCommit. Your driver may not support getAutoCommit() or setAutoCommit(). Requested setting: false. Cause: org.sqlite.SQLiteException: [SQLITE_LOCKED_SHAREDCACHE] Contention with a different database connection that shares the cache (database table is locked)
### The error may exist in mapper/MsgRecordDO-sqlmap-mappering.xml
### The error may involve com.super.mock.platform.agent.dal.daointerface.MsgRecordDAO.getRecord
### The error occurred while executing a query
### Cause: org.apache.ibatis.transaction.TransactionException: Error configuring AutoCommit. Your driver may not support getAutoCommit() or setAutoCommit(). Requested setting: false. Cause: org.sqlite.SQLiteException: [SQLITE_LOCKED_SHAREDCACHE] Contention with a different database connection that shares the cache (database table is locked)
解决方法
我终于自己解决了这个问题,并在下面分享了变通办法,以防将来其他人遇到类似问题。
遍历回调指示的源代码,我们有以下发现。
- SQLite内置默认启用了 auto commit ,这与MyBatis矛盾,因为MyBatis默认禁用 auto commit ,因为我们使用的是SqlSessionManager
- MyBatis将在使用方法
setDesiredAutoCommit
的连接初始化期间重写自动提交属性,该方法最终将调用SQLiteConnection#setAutoCommit
-
SQLiteConnection#setAutoCommit
将对数据库产生立即开始操作,该操作实际上是排他的,请查看下面的源代码屏幕截图以获取详细说明,因为我们将交易模式配置为 IMMEDIATE
<property name="driver.transaction_mode" value="IMMEDIATE"/>
因此,到目前为止,一个显而易见的解决方案是将交易模式更改为 DEFERRED 。此外,还考虑了使MyBatis和SQLite之间的 auto commit 设置相同的解决方案,但是,由于在初始化阶段无法设置SQLiteConnection的自动提交,因此未采用该解决方案,总是会发生 switching (从true到false,反之亦然),并且 switch 可能会导致上述错误,如果交易模式设置不正确
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。