一些版本信息:
- Jboss 6.4
- 波斯特格雷斯9.6
- 蕈毒蛋白CDI
- Postgres驱动程序42.2.20 JDBC 4
我遇到了一个问题,这个问题在我的系统中导致了灾难性的行为,从我的调试中,我可以推断出一个空闲事务似乎锁定了我的数据库中的一个表,导致应用程序冻结(某些锁没有被释放)。我已经能够停止冻结我在mybatis中设置的超时,但我不能弄清楚是什么首先导致了空闲事务。好消息是,似乎总是同一个UPDATE语句被阻塞。但是,我不能缩小查询/事务的范围,我看到的行为是我理解的。
以下是似乎总是锁定的查询(某些名称已更改,但此查询正常工作):
<update id="updateHealth">
UPDATE table d
SET fk_table_health_status_id =
(SELECT pk_table_health_status_id
FROM stat_table_health_status sdhs
WHERE sdhs.table_health_status = #{health})
<if test="health == 'Failed' || health == 'Other Failed'">
,last_failure = NOW(),
failure_count = failure_count + 1</if>
WHERE d.name = #{name}
</update>
用于调用查询的存储库文件:
@Stateless
public class Repository implements IRepository {
/**The device mapper. */
// CHECKSTYLE:OFF - SuppressWarnings - Bean is auto-generated by the iBatis mapper.
@SuppressWarnings("cdi-ambiguous-dependency")
@Inject
@Mapper
private IMapper mapper;
// more queries...
@Override
public void updateHealth(String name, String health) {
mapper.updateHealth(name, health);
}
// more queries...
}
这个查询并不总是冻结,但它发生得相当频繁。当它冻结时,我看到有一个空闲的事务,直到我关闭服务器或我设置的某个超时为止。
下面是我对Mybatis和Jboss的配置:
密贝蒂斯:
<configuration>
<settings>
<setting name="autoMappingBehavior" value="PARTIAL"/>
</settings>
<!-- Used to configure MyBatis environment to apply your SQL Maps to the database. -->
<environments default="development">
<environment id="development">
<transactionManager type="MANAGED" />
<dataSource type="JNDI">
<property name="data_source" value="${jdbc.url}" />
</dataSource>
</environment>
</environments>
<!-- The mappers configures the location of the xml mappers containing the CRUD functions ex against the database. -->
<mappers>
<package name="com/my/mapper/package"/>
</mappers>
</configuration>
Jboss数据源:
<subsystem xmlns="urn:jboss:domain:datasources:1.2">
<datasources>
<datasource jndi-name="java:jboss/datasources/PostgresDS" pool-name="PostgresDS" enabled="true" use-java-context="true">
<connection-url>jdbc:postgresql://localhost:5432/mydb</connection-url>
<driver>postgresql</driver>
<pool>
<min-pool-size>2</min-pool-size>
<max-pool-size>20</max-pool-size>
<prefill>true</prefill>
</pool>
<security>
<user-name>user</user-name>
<password>super_secret_password</password>
</security>
<validation>
<check-valid-connection-sql>SELECT 1</check-valid-connection-sql>
<validate-on-match>false</validate-on-match>
<background-validation>false</background-validation>
<use-fast-fail>false</use-fast-fail>
</validation>
</datasource>
JBoss事务:
<subsystem xmlns="urn:jboss:domain:transactions:1.5">
<core-environment>
<process-id>
<uuid/>
</process-id>
</core-environment>
<recovery-environment socket-binding="txn-recovery-environment" status-socket-binding="txn-status-manager"/>
<coordinator-environment default-timeout="1800"/>
</subsystem>
我已经在postgres中启用了锁监视,我经常看到这样日志:
2021-10-27 13:07:15 EDT LOG: process 15612 still waiting for ShareLock on transaction 10150 after 1005.830 ms
2021-10-27 13:07:15 EDT DETAIL: Process holding the lock: 13404. Wait queue: 15612.
2021-10-27 13:07:15 EDT CONTEXT: while updating tuple (1,24) in relation "dyn_device"
2021-10-27 13:07:15 EDT STATEMENT: UPDATE dyn d
SET fk_health_status_id =
(SELECT pk_health_status_id
FROM stat_health_status sdhs
WHERE sdhs.health_status = $1)
WHERE d.name = $2
让我感到困惑的是,在我的系统中,没有一个查询需要超过几毫秒的时间。没有一个疯狂的事务需要进行30个不同的查询,中间还需要REST调用。数据库中充满了大多数简单的CRUD操作。然而,这个日志却让人觉得一个事务需要超过一秒的时间......是JBOSS事务子系统没有提交事务吗?如果是这种情况,我如何强制它提交?我已经使用Postgres Lock Monitoring中的查询来帮助调试这个问题。每次系统冻结时,我都会看到我的事务没有被授予锁,另一个事务停留在“idle in transaction”状态。该查询还返回似乎导致空闲事务的查询/事务。但是,所显示的空闲查询看起来是随机的,与UPDATE正在访问的表无关。我看到过对完全不相关的表执行INSERT,也看到过对不同表执行SELECT。我还为Transaction子系统启用了跟踪日志记录。它显示了一个事务正在提交后,我的查询是锁定开始。我可以张贴,如果它会有帮助,但它的很多排序虽然。
说到这里,有没有人知道是什么导致了这个问题?事务是如何进入“idle in transaction”状态的?有没有人知道我还可以做些什么来调试这个问题?应用程序同步是否也起了作用?我尝试过将所有查询同步到被锁定的表(切换到@Singleton),但似乎没有效果。
1条答案
按热度按时间ccrfmcuu1#
所以我发现了问题所在。问题实际上不是数据库的错误,甚至不是正在使用的查询。结果是,我们的系统对我们的数据源使用了相同的事务子系统(Postgres数据库)和我们的JMS消息传递系统。当发送JMS消息时,它创建了一个事务,并且在该线程/事务的生命周期期间跟随的每个基于事务的动作都将被视为该原始事务的一部分。其中包括我们所有的数据库调用.....
这就解释了为什么像插入消息日志这样简单的查询会触及数据库中的所有关系。调试查询只显示了发送到数据库的第一个查询/语句,而不是在JMS消息的生命周期中使用的所有其他消息。有几种方法可以解决这个问题,但我的团队选择了最简单的方法,即阻止数据源使用JBoss提供的事务经理。
<datasource jndi-name="java:jboss/datasources/PostgresDS" jta="false" pool-name="PostgresDS" enabled="true" use-java-context="true">