SQLite 内存数据库间歇性遇到 SQLITE_LOCKED_SHAREDCACHE
SQLite in-memory database encounters SQLITE_LOCKED_SHAREDCACHE intermittently
我正在使用 mybatis 3.4.6 以及 org.xerial:sqlite-jdbc 3.28.0。下面是我使用启用了共享模式的 内存数据库的配置
db.driver=org.sqlite.JDBC
db.url=jdbc:sqlite:file::memory:?cache=shared
db.url
根据这个test class
是正确的
尽管根据我也报告的 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 是 built-in,默认启用 auto commit,这与默认禁用 auto commit 的 MyBatis 矛盾,因为我们正在使用 SqlSessionManager
- MyBatis 将在连接初始化期间使用方法
setDesiredAutoCommit
覆盖自动提交 属性,最终调用 SQLiteConnection#setAutoCommit
SQLiteConnection#setAutoCommit
会对数据库进行 begin immediate 操作,这实际上是独占的,查看下面的源代码截图以获得详细解释,因为我们将事务模式配置为立即
<property name="driver.transaction_mode" value="IMMEDIATE"/>
所以到目前为止,一个明显的解决方案是将事务模式更改为 DEFERRED。另外,MyBatis 和 SQLite 的 auto commit 设置相同的解决方案也被考虑过,但是没有采用,因为在期间无法设置 SQLiteConnection 的自动提交初始化阶段,总会有 switching(从 true 到 false,反之亦然),如果事务模式不是,switch 可能会导致上述错误正确设置
我正在使用 mybatis 3.4.6 以及 org.xerial:sqlite-jdbc 3.28.0。下面是我使用启用了共享模式的 内存数据库的配置
db.driver=org.sqlite.JDBC
db.url=jdbc:sqlite:file::memory:?cache=shared
db.url
根据这个test class
尽管根据我也报告的 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 是 built-in,默认启用 auto commit,这与默认禁用 auto commit 的 MyBatis 矛盾,因为我们正在使用 SqlSessionManager
- MyBatis 将在连接初始化期间使用方法
setDesiredAutoCommit
覆盖自动提交 属性,最终调用SQLiteConnection#setAutoCommit
SQLiteConnection#setAutoCommit
会对数据库进行 begin immediate 操作,这实际上是独占的,查看下面的源代码截图以获得详细解释,因为我们将事务模式配置为立即
<property name="driver.transaction_mode" value="IMMEDIATE"/>
所以到目前为止,一个明显的解决方案是将事务模式更改为 DEFERRED。另外,MyBatis 和 SQLite 的 auto commit 设置相同的解决方案也被考虑过,但是没有采用,因为在期间无法设置 SQLiteConnection 的自动提交初始化阶段,总会有 switching(从 true 到 false,反之亦然),如果事务模式不是,switch 可能会导致上述错误正确设置