10.2 模板事务
模板事务适合在一段局部代码里使用事务。它把固定的事务控制逻辑包起来:先 begin,正常结束就 commit,抛出异常或标记回滚时就回滚。
适合
- 普通 Java 程序中只想包住一段代码。
- 不想为
@Transactional准备代理对象。 - 希望避免重复写 try/catch/finally。
不适合
- 事务边界就是 Service 方法,且项目已有代理能力。
- 需要手动保留多个
TransactionStatus,并按指定顺序提交或回滚。
本页使用 dbVisitor 的事务模板,不是 Spring 的同名类。execute 声明抛出 Throwable,调用方法需处理或声明它。序列 SQL 示例适用于 H2 等支持 NEXT VALUE FOR 的数据库。
基本用法
创建 TransactionTemplate
import javax.sql.DataSource;
import net.hasor.dbvisitor.transaction.TransactionManager;
import net.hasor.dbvisitor.transaction.TransactionTemplate;
import net.hasor.dbvisitor.transaction.TransactionTemplateManager;
import net.hasor.dbvisitor.transaction.support.TransactionHelper;
DataSource dataSource = ...;
TransactionManager txManager = TransactionHelper.txManager(dataSource);
TransactionTemplate txTemplate = new TransactionTemplateManager(txManager);
在事务中返回结果
Long orderId = txTemplate.execute(tranStatus -> {
Long newOrderId = jdbcTemplate.queryForObject(
"select next value for seq_order",
Long.class
);
jdbcTemplate.executeUpdate(
"insert into orders(id, user_id) values(?, ?)",
new Object[] { newOrderId, userId }
);
jdbcTemplate.executeUpdate(
"insert into order_item(order_id, sku_id) values(?, ?)",
new Object[] { newOrderId, skuId }
);
return newOrderId;
});
执行效果:
- 回调正常返回时,模板提交事务,并把
newOrderId作为execute的返回值。 - 回调抛出异常时,模板把事务标记为回滚,然后重新抛出异常。
无返回值代码块
使用 TransactionCallbackWithoutResult
import net.hasor.dbvisitor.transaction.TransactionCallbackWithoutResult;
txTemplate.execute((TransactionCallbackWithoutResult) tranStatus -> {
jdbcTemplate.executeUpdate(
"delete from order_item where order_id = ?",
orderId
);
jdbcTemplate.executeUpdate(
"delete from orders where id = ?",
orderId
);
});
主动标记回滚
有些场景不想抛异常,但希望当前事务最终回滚,可以在回调里调用 tranStatus.setRollback()。
校验失败时回滚,但返回业务结果
Boolean success = txTemplate.execute(tranStatus -> {
int updated = jdbcTemplate.executeUpdate(
"update sku_stock set quantity = quantity - ? where sku_id = ? and quantity >= ?",
new Object[] { quantity, skuId, quantity }
);
if (updated == 0) {
tranStatus.setRollback();
return false;
}
jdbcTemplate.executeUpdate(
"insert into stock_log(sku_id, quantity) values(?, ?)",
new Object[] { skuId, quantity }
);
return true;
});
执行效果:
- 库存充足时,扣库存和日志一起提交,返回
true。 - 库存不足时,不抛异常,但事务回滚,返回
false。
指定传播行为和隔离级别
用独立事务写审计日志
import net.hasor.dbvisitor.transaction.Isolation;
import net.hasor.dbvisitor.transaction.Propagation;
txTemplate.execute(tranStatus -> {
jdbcTemplate.executeUpdate(
"insert into order_audit(order_id, action) values(?, ?)",
new Object[] { orderId, "CREATE" }
);
return null;
}, Propagation.REQUIRES_NEW, Isolation.READ_COMMITTED);
如果这段代码在外层事务里执行,REQUIRES_NEW 会挂起外层事务,打开新的连接执行审计日志事务。日志提交或回滚完成后,再恢复外层事务。
获取 TransactionTemplate
普通 Java 程序
TransactionManager txManager = TransactionHelper.txManager(dataSource);
TransactionTemplate txTemplate = new TransactionTemplateManager(txManager);
依赖注入环境
public class OrderService {
// @Inject < Guice、Solon 和 Hasor
// @Resource or @Autowired < Spring
private TransactionTemplate txTemplate;
}
相关集成: