You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 00:06:07