【发布时间】:2021-04-14 02:24:56
【问题描述】:
我尝试执行事务操作并故意抛出异常,以验证是否已完成回滚但未执行回滚。
PostgreSQL 数据库版本为 12.1-1,基于 Docker。
这里是包含@Transactional注解的服务:
@Service
public class MyTestService {
@Autowired
private DocumentDataDao documentDataDao;
@Transactional
public void test() {
DocumentData data = new DocumentData();
data.setData(UUID.randomUUID().toString());
documentDataDao.create(data);
throw new IllegalArgumentException("Test rollback");
}
}
create 函数使用NamedParameterJdbcTemplate 插入数据:
String statement = String.format("INSERT INTO %s (%s) VALUES (%s) RETURNING %s", tableName,
String.join(",", insertingColumns), String.join(",", values),
String.join(",", returningColumns));
return getNamedJdbcTemplate().queryForObject(statement, parameters, getRowMapper());
而test 函数是从另一个服务调用的:
@Service
public class ApplicationStartupListener {
private Logger log = LoggerFactory.getLogger(ApplicationStartupListener.class);
@Autowired
private MyTestService testService;
@PostConstruct
public void init() {
try {
testService.test();
} catch (Exception e) {
log.error("fail to start", e);
}
}
}
调试的时候我发现如果回滚没有被执行,那是因为事务是IDLE。
这是来自PgConnection 和executeTransactionCommand 的rollback 函数没有被执行:
public void rollback() throws SQLException {
checkClosed();
if (autoCommit) {
throw new PSQLException(GT.tr("Cannot rollback when autoCommit is enabled."),
PSQLState.NO_ACTIVE_SQL_TRANSACTION);
}
if (queryExecutor.getTransactionState() != TransactionState.IDLE) {
executeTransactionCommand(rollbackQuery);
}
}
任何关于为什么事务被标记为空闲并停止执行回滚方法的提示将不胜感激。
编辑 (1)
作为@M。 Deinum 提到,使用@PostConstruct 时不能保证已创建事务代理。这就是我使用ApplicationRunner 进行测试的原因:
@Component
public class AppStartupRunner implements ApplicationRunner {
@Autowired
private MyTestService testService;
@Override
public void run(ApplicationArguments args) throws Exception {
testService.test();
}
}
但这也没有用。
我还尝试在应用程序启动后不久运行 test 方法,方法是使用 RestController 并向其发送 HTTP 请求,但仍然是同样的问题。
@RestController
public class AppController {
@Autowired
private MyTestService testService;
@GetMapping("/test")
public ResponseEntity<Object> test() {
testService.test();
return ResponseEntity.ok().build();
}
}
编辑 (2)
我将 PostgreSQL JDBC 版本从 42.2.2 升级到 42.2.18(截至目前最新),但尝试回滚时连接仍处于空闲状态。
编辑 (3)
我在 git 存储库中重现了该问题:https://github.com/Martin-Hogge/spring-boot-postgresql-transactional-example/tree/master。
【问题讨论】:
-
你试过这个 rollbackFor => @Transactional(rollbackFor = Exception.class)
-
是的,我得到相同的结果 -> 没有回滚。
-
在使用
@PostConstruct时不能保证已经创建了事务代理。您应该使用适当的侦听器或使用ApplicationRunner,它会在一切开始并完全初始化后执行。 -
感谢您的见解。不幸的是,这不是问题 - 我用详细信息编辑了帖子。
-
并且
idle事务没有问题,并不表示有n个未处理的事务。idle in transaction表示一个打开的事务。
标签: java postgresql spring-boot transactions