空闲事务 mybatis jboss 6.4 postgres 9.6
Idle transactions mybatis jboss 6.4 postgres 9.6
部分版本信息:
- Jboss6.4
- Postgres 9.6
- mybatis-3 CDI
- Postgres 驱动程序 42.2.20 JDBC 4
我遇到了一个问题,该问题导致我的系统出现非常灾难性的行为。从我的调试中,我已经能够推断出一个空闲事务似乎在我的数据库中锁定了一个 table,导致应用程序冻结(某些锁没有被释放)。我已经能够停止在 mybatis 中冻结我的设置超时,但我无法首先弄清楚是什么导致了空闲事务。好消息是,似乎被阻止的总是相同的 UPDATE 语句。但是,我无法缩小 query/trans
curring 并且我看到了我理解的行为。
这里是似乎总是锁定的查询(一些名称已更改但此查询正常工作):
<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 的配置:
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 = )
WHERE d.name =
让我感到困惑的是,我的系统中没有一个查询应该花费比几毫秒更长的时间。没有疯狂的事务会在中间调用 REST 调用 30 个不同的查询。数据库充满了大部分简单的 CRUD 操作。然而这个日志看起来好像一个事务花费的时间比一秒钟还长...... JBOSS 事务子系统是否没有提交事务?如果是这种情况,我该如何强制它提交?我一直在使用来自 Postgres Lock Monitoring 的查询来帮助调试此问题。每次系统冻结时,我都会看到我的事务没有被授予锁定,而另一个事务则停留在“事务中空闲”状态。该查询还 returns queries/transactions 似乎导致了空闲事务。但是,显示的空闲查询似乎是随机的,与 UPDATE 正在访问的 table 无关。我已经看到插入到完全不相关的 tables 以及 SELECT 到不同的 tables。我还为事务子系统启用了跟踪日志记录。它显示了在我的锁定查询开始后立即提交的事务。我可以 post 如果它有帮助,但它有很多排序。
话虽如此,有人知道是什么导致了这个问题吗?事务如何真正进入“事务中空闲”状态?有谁知道我还能做些什么来调试它?应用程序同步可以发挥作用吗?我已经尝试将所有查询同步到被锁定的 table(切换到 @Singleton),但这似乎没有用。
所以我发现了问题所在。这个问题真的不是数据库的错,甚至不是正在使用的查询。事实证明,我们的系统为我们的数据源(Postgres 数据库)和我们的 JMS 消息传递系统使用相同的事务子系统。发送 JMS 消息时,它会创建一个事务,并且在该 tread/transaction 的生命周期中遵循的每个基于事务的操作都将被视为该原始事务的一部分。其中包括我们所有的数据库调用.....
这解释了为什么像插入消息日志这样简单的查询会触及我们在数据库中的所有关系。调试查询只显示第一个 query/statement 发送到数据库,而不是 JMS 消息生命周期中使用的所有其他查询。有几种方法可以解决此问题,但我的团队选择了最简单的方法,即阻止数据源使用 JBoss 提供的事务管理器。
<datasource jndi-name="java:jboss/datasources/PostgresDS" jta="false" pool-name="PostgresDS" enabled="true" use-java-context="true">
部分版本信息:
- Jboss6.4
- Postgres 9.6
- mybatis-3 CDI
- Postgres 驱动程序 42.2.20 JDBC 4
我遇到了一个问题,该问题导致我的系统出现非常灾难性的行为。从我的调试中,我已经能够推断出一个空闲事务似乎在我的数据库中锁定了一个 table,导致应用程序冻结(某些锁没有被释放)。我已经能够停止在 mybatis 中冻结我的设置超时,但我无法首先弄清楚是什么导致了空闲事务。好消息是,似乎被阻止的总是相同的 UPDATE 语句。但是,我无法缩小 query/trans curring 并且我看到了我理解的行为。
这里是似乎总是锁定的查询(一些名称已更改但此查询正常工作):
<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 的配置:
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 = )
WHERE d.name =
让我感到困惑的是,我的系统中没有一个查询应该花费比几毫秒更长的时间。没有疯狂的事务会在中间调用 REST 调用 30 个不同的查询。数据库充满了大部分简单的 CRUD 操作。然而这个日志看起来好像一个事务花费的时间比一秒钟还长...... JBOSS 事务子系统是否没有提交事务?如果是这种情况,我该如何强制它提交?我一直在使用来自 Postgres Lock Monitoring 的查询来帮助调试此问题。每次系统冻结时,我都会看到我的事务没有被授予锁定,而另一个事务则停留在“事务中空闲”状态。该查询还 returns queries/transactions 似乎导致了空闲事务。但是,显示的空闲查询似乎是随机的,与 UPDATE 正在访问的 table 无关。我已经看到插入到完全不相关的 tables 以及 SELECT 到不同的 tables。我还为事务子系统启用了跟踪日志记录。它显示了在我的锁定查询开始后立即提交的事务。我可以 post 如果它有帮助,但它有很多排序。
话虽如此,有人知道是什么导致了这个问题吗?事务如何真正进入“事务中空闲”状态?有谁知道我还能做些什么来调试它?应用程序同步可以发挥作用吗?我已经尝试将所有查询同步到被锁定的 table(切换到 @Singleton),但这似乎没有用。
所以我发现了问题所在。这个问题真的不是数据库的错,甚至不是正在使用的查询。事实证明,我们的系统为我们的数据源(Postgres 数据库)和我们的 JMS 消息传递系统使用相同的事务子系统。发送 JMS 消息时,它会创建一个事务,并且在该 tread/transaction 的生命周期中遵循的每个基于事务的操作都将被视为该原始事务的一部分。其中包括我们所有的数据库调用.....
这解释了为什么像插入消息日志这样简单的查询会触及我们在数据库中的所有关系。调试查询只显示第一个 query/statement 发送到数据库,而不是 JMS 消息生命周期中使用的所有其他查询。有几种方法可以解决此问题,但我的团队选择了最简单的方法,即阻止数据源使用 JBoss 提供的事务管理器。
<datasource jndi-name="java:jboss/datasources/PostgresDS" jta="false" pool-name="PostgresDS" enabled="true" use-java-context="true">