SQLite内存数据库偶尔遇到SQLITE_LOCKED_SHAREDCACHE。

huangapple go评论66阅读模式
英文:

SQLite in-memory database encounters SQLITE_LOCKED_SHAREDCACHE intermittently

问题

Below is your provided content translated into Chinese:

我正在使用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类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
===============================================================

SQLite内存数据库偶尔遇到SQLITE_LOCKED_SHAREDCACHE。

附件:

异常如下:

org.apache.ibatis.exceptions.PersistenceException: 
### 查询数据库时出错原因org.apache.ibatis.transaction.TransactionException: 配置AutoCommit时出错您的驱动程序可能不支持getAutoCommit()或setAutoCommit()所请求的设置false原因org.sqlite.SQLiteException: [SQLITE_LOCKED_SHAREDCACHE] 与共享缓存的其他数据库连接发生争用数据库表被锁定
### 错误可能存在于mapper/MsgRecordDO-sqlmap-mappering.xml
### 错误涉及com.super.mock.platform.agent.dal.daointerface.MsgRecordDAO.getRecord
### 执行查询时发生错误
### 原因org.apache.ibatis.transaction.TransactionException: 配置AutoCommit时出错您的驱动程序可能不支持getAutoCommit()或setCommit()所请求的设置false原因org.sqlite.SQLiteException: [SQLITE_LOCKED_SHAREDCACHE] 与共享缓存的其他数据库连接发生争用数据库表被锁定
英文:

I am using mybatis 3.4.6 along with org.xerial:sqlite-jdbc 3.28.0. Below is my configuration to use an in-memory database with shared mode enabled

db.driver=org.sqlite.JDBC
db.url=jdbc:sqlite:file::memory:?cache=shared

The db.url is correct according to this test class

And I managed to setup the correct transaction isolation level with below mybatis configuration though there is a typo of property read_uncommitted according to this issue which is reported by me as well

&lt;environment id=&quot;${db.env}&quot;&gt;
    &lt;transactionManager type=&quot;jdbc&quot;/&gt;
    &lt;dataSource type=&quot;POOLED&quot;&gt;
        &lt;property name=&quot;driver&quot; value=&quot;${db.driver}&quot; /&gt;
        &lt;property name=&quot;url&quot; value=&quot;${db.url}&quot;/&gt;
        &lt;property name=&quot;username&quot; value=&quot;${db.username}&quot; /&gt;
        &lt;property name=&quot;password&quot; value=&quot;${db.password}&quot; /&gt;
        &lt;property name=&quot;defaultTransactionIsolationLevel&quot; value=&quot;1&quot; /&gt;
        &lt;property name=&quot;driver.synchronous&quot; value=&quot;OFF&quot; /&gt;
        &lt;property name=&quot;driver.transaction_mode&quot; value=&quot;IMMEDIATE&quot;/&gt;
        &lt;property name=&quot;driver.foreign_keys&quot; value=&quot;ON&quot;/&gt;
    &lt;/dataSource&gt;
&lt;/environment&gt;

This line of configuration

  &lt;property name=&quot;defaultTransactionIsolationLevel&quot; value=&quot;1&quot; /&gt;

does the trick to set the correct value of PRAGMA read_uncommitted

I am pretty sure of it since I debugged the underneath code which initialize the connection and check the value has been set correctly

However with the above setting, my program still encounters SQLITE_LOCKED_SHAREDCACHE intermittently while reading, which I think it shouldn't happen according the description highlighted in the red rectangle of below screenshot. I want to know the reason and how to resolve it, though the occurring probability of this error is low.

Any ideas would be appreciated!!

The debug configurations is below


===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
===============================================================

SQLite内存数据库偶尔遇到SQLITE_LOCKED_SHAREDCACHE。

Attachments:

The exception is below

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)

答案1

得分: 1

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

首先,我们能够获取下面显示的异常的完整调用堆栈
SQLite内存数据库偶尔遇到SQLITE_LOCKED_SHAREDCACHE。

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

  1. SQLite内置了默认启用的_auto commit_,这与MyBatis相矛盾,因为我们使用SqlSessionManager,默认情况下禁用_auto commit_
  2. MyBatis会在连接初始化期间覆盖自动提交属性,使用方法setDesiredAutoCommit,最终调用SQLiteConnection#setAutoCommit
  3. SQLiteConnection#setAutoCommit将针对数据库执行立即开始操作,实际上是排他的,请查看下面的源代码截图以获取详细说明,因为我们将事务模式配置为IMMEDIATE

&lt;property name=&quot;driver.transaction_mode&quot; value=&quot;IMMEDIATE&quot;/&gt;

SQLite内存数据库偶尔遇到SQLITE_LOCKED_SHAREDCACHE。
SQLite内存数据库偶尔遇到SQLITE_LOCKED_SHAREDCACHE。

因此,到目前为止,明显的解决方案是将事务模式更改为DEFERRED。此外,还考虑了使MyBatis和SQLite之间的_auto commit_设置相同的解决方案,但是由于在初始化阶段无法设置SQLiteConnection的自动提交,所以没有采纳,如果事务模式未正确设置,则切换(从true到false或反之亦然)将可能导致上述错误。

英文:

I finally resolved this issue by myself and share the workaround below in case someone else encounters similar issue in the future.

First of all, we're able to get the completed call stack of the exception shown below
SQLite内存数据库偶尔遇到SQLITE_LOCKED_SHAREDCACHE。

Going through the source code indicated by the callback, we have below findings.

  1. SQLite is built-in with auto commit enabled by default which is contradict with MyBatis which disables auto commit by default since we're using SqlSessionManager
  2. MyBatis would override the auto commit property during connection initialization using method setDesiredAutoCommit which finally invokes SQLiteConnection#setAutoCommit
  3. SQLiteConnection#setAutoCommit would incur a begin immediate operation against the database which is actually exclusive, check out below source code screenshots for detailed explanation since we configure our transaction mode to be IMMEDIATE

&lt;property name=&quot;driver.transaction_mode&quot; value=&quot;IMMEDIATE&quot;/&gt;

SQLite内存数据库偶尔遇到SQLITE_LOCKED_SHAREDCACHE。
SQLite内存数据库偶尔遇到SQLITE_LOCKED_SHAREDCACHE。

So until now, An apparent solution is to change the transaction mode to be DEFERRED. Furthermore, the solution of making the auto commit setting the same between MyBatis and SQLite has been considered as well, however, it's not adopted since there is no way to set the auto commit of SQLiteConnection during initialization stage, there would be always switching (from true to false or vice versa) and switch would cause the above error probably if transaction mode is not set properly

huangapple
  • 本文由 发表于 2020年8月11日 23:47:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/63361787.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定