我目前正在调试一个使用Modeshape存储值的应用程序,并且最近出现了一些随机错误。通过广泛的日志记录和使用P6Spy检查内部调用,我发现了一些东西。
对于上下文,Modeshape 有一个基于节点的内部数据模型,但最终它们被保存在数据库中(在我们的例子中,是一个 Oracle DB)。基本上,一个表 MP_CONFIG_CFGMGMT_REPOSITORY 用于此目的,它包含一个 ID 字段、一个修改日期和一个带有节点内容的 BLOB(编码为二进制 JSON)。
在某些时候,Modeshape 需要编辑一个节点,因此更新 MP_CONFIG_CFGMGMT_REPOSITORY 中的相应记录(通过 ID)更改内容字段。此更新在事务中提交。
在那次提交之后,两个线程(其中一个是更新和提交表的同一线程)对同一条记录进行查询。使用 P6Spy,我可以确认,有时,其中一个查询返回一个内容字段,其中包含提交更新之前的值,而另一个查询返回正确的更新值。这会导致代码中进一步出现问题。
阅读 Modeshape 代码,我发现它使用隔离级别创建连接Connection.TRANSACTION_READ_COMMITTED
(并且查询被确认在提交更新后发生),因此它不会是脏读的问题。
数据源是在 JBoss(部署我的应用程序的应用程序服务器)中定义的 JNDI 资源,使用以下配置定义:
<datasource jta="false" jndi-name="java:jboss/nameOfDatasource" pool-name="nameOfDatasource" enabled="true" use-java-context="true" statistics-enabled="true">
<connection-url>jdbc:oracle:thin:@//db-host:6789/DB_NAME</connection-url>
<driver>oracle</driver>
<pool>
<min-pool-size>100</min-pool-size>
<max-pool-size>100</max-pool-size>
</pool>
<security>
<user-name>${USERNAME}</user-name>
<password>${PASSWORD}</password>
</security>
<validation>
<valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.oracle.OracleValidConnectionChecker"/>
<validate-on-match>false</validate-on-match>
<background-validation>true</background-validation>
<background-validation-millis>30000</background-validation-millis>
<exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.oracle.OracleExceptionSorter"/>
</validation>
<statement>
<prepared-statement-cache-size>25</prepared-statement-cache-size>
</statement>
</datasource>
...
<drivers>
...
<driver name="oracle" module="org.jdbc.oracle">
<driver-class>oracle.jdbc.driver.OracleDriver</driver-class>
</driver>
</drivers>
我的问题是:这种行为的可能原因是什么?可能与 Oracle 本身有关?或者可能是 JBoss 在 Oracle 和应用程序之间进行的中间设置?
Oracle 版本:19c 企业版 Release 19.0.0.0.0
我读过 Oracle 有LOB 缓存选项,但建议仅在“如果您很少访问 LOB 或 LOB 非常大”时避免使用它,这里不是这种情况