Jboss 6.4+Postgres 9.6环境下MyBatis出现空闲事务锁表问题求助
环境版本信息
- Jboss 6.4
- Postgres 9.6
- mybatis-3 CDI
- Postgres Driver 42.2.20 JDBC 4
故障概述
系统目前出现了严重的运行故障,经初步排查推断是存在空闲事务锁定了数据库表,导致锁无法释放进而引发应用冻结。通过在MyBatis中设置超时参数暂时解决了冻结问题,但始终无法定位空闲事务的根本诱因。目前可以确认被阻塞的始终是同一条UPDATE语句,但无法定位具体是哪个查询/事务引发了该问题,观察到的现象也存在诸多疑点。
被锁定的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>
调用该查询的Repository文件代码
@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配置
<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操作。但上述日志显示事务耗时超过1秒,是否是JBOSS的事务子系统未正常提交事务?如果是该原因该如何强制事务提交?
使用Postgres锁监控查询语句辅助排查,每次系统冻结时都能看到待执行事务无法获取锁,同时存在另一个处于idle in transaction状态的事务。查询返回的引发空闲事务的语句看起来都是随机的,和被锁表完全无关,完全不相关表的INSERT语句、其他表的SELECT语句都曾出现在空闲事务中。
也开启了事务子系统的trace日志,日志显示被阻塞的查询启动后立刻就有一个事务被提交,相关日志内容较多需要梳理后可提供。
想请教以下问题:
- 什么原因可能引发该问题?
- 事务是如何进入idle in transaction状态的?
- 还有哪些排查手段可以使用?
- 是否和应用层的同步机制有关?曾尝试将所有对被锁表的查询操作改为同步(切换为@Singleton),但没有解决问题。
内容的提问来源于stack exchange,提问作者Cody Herbst
相关产品推荐
相关产品推荐

