0

我正在使用 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根据这个测试类是正确

我设法使用以下 mybatis 配置设置了正确的事务隔离级别,尽管根据我也报告的这个问题,属性 read_uncommitted 有一个错字

<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)
4

1 回答 1

0

我终于自己解决了这个问题,并在下面分享了解决方法,以防其他人将来遇到类似问题。

首先,我们能够得到如下所示的异常的完整调用堆栈 在此处输入图像描述

通过回调指示的源代码,我们有以下发现。

  1. SQLite 是内置的,默认启用自动提交,这与 MyBatis 相矛盾,MyBatis 默认禁用自动提交,因为我们使用的是 SqlSessionManager
  2. setDesiredAutoCommitMyBatis 将在连接初始化期间使用最终调用的方法覆盖自动提交属性SQLiteConnection#setAutoCommit
  3. SQLiteConnection#setAutoCommit由于我们将事务模式配置IMMEDIATE

<property name="driver.transaction_mode" value="IMMEDIATE"/>

在此处输入图像描述 在此处输入图像描述

所以到目前为止,一个明显的解决方案是将事务模式更改为DEFERRED。另外,也考虑过让MyBatis和SQLite的自动提交设置相同的方案,但是没有采用,因为初始化阶段无法设置SQLiteConnection的自动提交,总是会切换(从true 到 false 或反之亦然),如果事务模式设置不正确,切换可能会导致上述错误

于 2020-10-21T10:06:44.087 回答