在 Spring Boot 应用中结合使用 PostgreSQL 的 dblink 和 @Transactional
注解时,需要注意事务传播的特殊性,因为 dblink 连接默认是自动提交的。
1. 基本问题分析
dblink 连接默认是自动提交(auto-commit)模式,这意味着每个 dblink_exec 调用都会立即提交,不受外层 Spring 事务管理器的控制。
2. 解决方案
@Service
@RequiredArgsConstructor
public class DataTransferService {
private final JdbcTemplate jdbcTemplate;
@Transactional
public void transferDataWithRollback() {
try {
// 建立连接并禁用自动提交
jdbcTemplate.execute(
"SELECT dblink_connect('transfer_conn', " +
"'dbname=remote_db user=user password=pass host=remote_host port=5432 autocommit=off')");
// 开始事务块
jdbcTemplate.execute("BEGIN");
// 本地操作
jdbcTemplate.update("INSERT INTO local_audit (operation) VALUES ('data transfer started')");
// 远程操作
jdbcTemplate.execute(
"SELECT dblink_exec('transfer_conn', " +
"'INSERT INTO remote_data (id, content) VALUES (1, ''test content'')')");
// 模拟业务逻辑
if (someBusinessCondition()) {
throw new RuntimeException("Business validation failed");
}
// 提交事务
jdbcTemplate.execute("COMMIT");
} catch (Exception e) {
// 回滚事务
jdbcTemplate.execute("ROLLBACK");
throw new DataTransferException("Data transfer failed", e);
} finally {
// 确保连接关闭
jdbcTemplate.execute("SELECT dblink_disconnect('transfer_conn')");
}
}
private boolean someBusinessCondition() {
// 你的业务逻辑
return false;
}
}