Spring @Transactional timeout 在 DB2 中无法正常工作
Spring @Transactional timeout does not work as expected with DB2
我们有一个与 DB2 (LUW) 数据库集成的 spring 应用程序。
在特定的流程中,我们有一个用 @Transactional(timeout=60)
注释的方法
在数据库重负载时,我们观察到上述 60 秒的超时未能抛出
准时例外。它仅在数据库处理成功完成或
出现错误。
失败的信息如下:
2020-02-21 18:45:32,463 ERROR ... Transaction timed out: deadline was Fri Feb 21 18:40:14 EET 2020
请注意,在数据库释放资源后抛出异常,在特定情况下会出现锁定超时错误,由于配置的事务超时,比我预期的晚了大约 5 分钟。
我试图通过在数据库中手动造成延迟来重现此行为。具体来说,我打电话
来自我的应用程序的睡眠 DB2 过程,时间长于配置的事务超时。我的测试也是一样的结果,只有在sleep操作成功结束后才抛出异常。
我想检查另一个数据库的类似情况,因此我创建了一个简单的 Spring 引导项目,其中包含 2 个不同的配置文件,一个用于 DB2,一个用于 Postgres。
运行 这个例子我观察到 DB2 的类似行为,即事务超时不会导致任何错误,或者它只在为 DB2 配置的睡眠时间(30 秒)之后才执行,这大于配置的事务超时(10 秒),结束。
相反,Postgres 的行为或多或少符合我的预期。与 DB 的连接在事务超时时间已过(10 秒)的确切时刻以异常结束,而不等待睡眠操作完成(30 秒)。
示例项目是here。此处描述的示例如下:
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class DemoService {
@Autowired
private DemoRepository repository;
@Transactional(timeout = 10)
public void sleep() {
repository.sleep();
}
}
package com.example.demo;
public interface DemoRepository {
void sleep();
}
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
@Profile("db2")
public class Db2DemoRepository implements DemoRepository {
@Autowired
private JdbcTemplate template;
@Override
public void sleep() {
template.execute("call SYSIBMADM.DBMS_ALERT.SLEEP(30)");
}
}
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
@Profile("postgres")
public class PostgresDemoRepository implements DemoRepository {
@Autowired
private JdbcTemplate template;
@Override
public void sleep() {
template.execute("select pg_sleep(30);");
}
}
我猜想事务超时设置了 Postgres 中的查询超时,而在 DB2 中却没有这样做。
我还尝试了以下 DB2 配置属性的几个值,但没有任何运气:timerLevelForQueryTimeOut, interruptProcessingMode, queryTimeout
.
所以我的问题是:
- 我尝试重现问题并测试多个数据库的方法是否有意义,或者我是否遗漏了什么?
- 这更重要,: 有没有办法让 DB2 连接在事务超时达到其限制的那一刻失败?
自从我发布问题以来已经有一段时间没有人发布答案我将从我的问题的编辑部分移动我的发现,这里:
解决方案似乎是设置 DB2 配置 属性 queryTimeoutInterruptProcessingMode=2
(而不是我最初认为的 interruptProcessingMode)
示例:jdbc:db2://localhost:50000/demo:queryTimeoutInterruptProcessingMode=2;
修改后,事务超时结束时抛出异常。不过还是想听听专家的意见。例如,修改特定的 属性 是否安全?有什么影响?
我们有一个与 DB2 (LUW) 数据库集成的 spring 应用程序。
在特定的流程中,我们有一个用 @Transactional(timeout=60)
在数据库重负载时,我们观察到上述 60 秒的超时未能抛出 准时例外。它仅在数据库处理成功完成或 出现错误。
失败的信息如下:
2020-02-21 18:45:32,463 ERROR ... Transaction timed out: deadline was Fri Feb 21 18:40:14 EET 2020
请注意,在数据库释放资源后抛出异常,在特定情况下会出现锁定超时错误,由于配置的事务超时,比我预期的晚了大约 5 分钟。
我试图通过在数据库中手动造成延迟来重现此行为。具体来说,我打电话 来自我的应用程序的睡眠 DB2 过程,时间长于配置的事务超时。我的测试也是一样的结果,只有在sleep操作成功结束后才抛出异常。
我想检查另一个数据库的类似情况,因此我创建了一个简单的 Spring 引导项目,其中包含 2 个不同的配置文件,一个用于 DB2,一个用于 Postgres。 运行 这个例子我观察到 DB2 的类似行为,即事务超时不会导致任何错误,或者它只在为 DB2 配置的睡眠时间(30 秒)之后才执行,这大于配置的事务超时(10 秒),结束。
相反,Postgres 的行为或多或少符合我的预期。与 DB 的连接在事务超时时间已过(10 秒)的确切时刻以异常结束,而不等待睡眠操作完成(30 秒)。
示例项目是here。此处描述的示例如下:
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class DemoService {
@Autowired
private DemoRepository repository;
@Transactional(timeout = 10)
public void sleep() {
repository.sleep();
}
}
package com.example.demo;
public interface DemoRepository {
void sleep();
}
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
@Profile("db2")
public class Db2DemoRepository implements DemoRepository {
@Autowired
private JdbcTemplate template;
@Override
public void sleep() {
template.execute("call SYSIBMADM.DBMS_ALERT.SLEEP(30)");
}
}
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
@Profile("postgres")
public class PostgresDemoRepository implements DemoRepository {
@Autowired
private JdbcTemplate template;
@Override
public void sleep() {
template.execute("select pg_sleep(30);");
}
}
我猜想事务超时设置了 Postgres 中的查询超时,而在 DB2 中却没有这样做。
我还尝试了以下 DB2 配置属性的几个值,但没有任何运气:timerLevelForQueryTimeOut, interruptProcessingMode, queryTimeout
.
所以我的问题是:
- 我尝试重现问题并测试多个数据库的方法是否有意义,或者我是否遗漏了什么?
- 这更重要,: 有没有办法让 DB2 连接在事务超时达到其限制的那一刻失败?
自从我发布问题以来已经有一段时间没有人发布答案我将从我的问题的编辑部分移动我的发现,这里:
解决方案似乎是设置 DB2 配置 属性 queryTimeoutInterruptProcessingMode=2
(而不是我最初认为的 interruptProcessingMode)
示例:jdbc:db2://localhost:50000/demo:queryTimeoutInterruptProcessingMode=2;
修改后,事务超时结束时抛出异常。不过还是想听听专家的意见。例如,修改特定的 属性 是否安全?有什么影响?