跳到主要内容

数据库事务

dbVisitor 提供一套轻量的本地事务能力,用来把多次数据库操作放进同一个提交或回滚边界里。它适合处理“创建订单后扣库存”、“写主表后写明细”、“一段逻辑中部分操作需要独立提交”这类场景。

事务由 TransactionManager 管理,一个事务管理器绑定一个 DataSource。在事务中,dbVisitor 会把当前线程上的数据库连接交给 JdbcTemplate、Mapper、BaseMapper、LambdaTemplate 等 API 复用;事务结束时再统一提交或回滚。

信息

事务需要 JDBC 驱动和数据库支持,不能用于不支持事务的适配器。dbVisitor 管理的是本地事务,不是分布式事务。多个 DataSource 可以分别绑定事务拦截器,但不同数据库之间不会自动具备两阶段提交能力。

先选使用方式​

使用方式适合不适合入口
注解式事务Service 方法边界清楚,希望业务代码最干净没有代理/拦截器,或者事务边界需要动态决定注解式事务
模板事务只有局部代码需要事务,希望自动处理提交和回滚需要手动控制多个事务状态的提交顺序模板事务
编程式事务需要完全控制 begin、commit、rollBack常规业务方法,容易写出重复 try/catch编程式事务

一般建议:

  • 在 Spring、Solon、Guice、Hasor 这类带 DI/代理能力的项目里,优先用注解式事务。
  • 在普通 Java 程序、脚本式任务、局部事务代码里,优先用模板事务。
  • 只有确实需要手动控制事务状态时,再使用编程式事务。

一个完整效果​

下面以支持序列及本地事务的数据库(例如 H2)为例,表和序列需预先创建,并通过 事务代理 调用方法。示例希望达成一个效果:创建订单和订单明细必须同时成功;任意一步失败,都要一起回滚。

OrderService.java
import net.hasor.dbvisitor.jdbc.JdbcTemplate;
import net.hasor.dbvisitor.transaction.Transactional;

public class OrderService {
private final JdbcTemplate jdbcTemplate;

public OrderService(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}

@Transactional
public long createOrder(long userId, long skuId, int quantity) throws java.sql.SQLException {
Long orderId = jdbcTemplate.queryForObject(
"select next value for seq_order",
Long.class
);

jdbcTemplate.executeUpdate(
"insert into orders(id, user_id) values(?, ?)",
new Object[] { orderId, userId }
);
jdbcTemplate.executeUpdate(
"insert into order_item(order_id, sku_id, quantity) values(?, ?, ?)",
new Object[] { orderId, skuId, quantity }
);
jdbcTemplate.executeUpdate(
"update sku_stock set quantity = quantity - ? where sku_id = ?",
new Object[] { quantity, skuId }
);
return orderId;
}
}

如果 order_item 插入成功后,扣库存 SQL 抛出异常,事务拦截器会把当前事务标记为回滚,最后执行回滚。最终效果是:订单、明细、库存都不会留下半成品数据。

代码结构​

事务相关代码都在 net.hasor.dbvisitor.transaction 包下:

类型作用常见使用位置
@Transactional声明方法或类需要事务Service 方法、业务入口方法
Propagation控制当前方法如何加入、创建、挂起事务注解、模板、编程式 begin
Isolation控制数据库并发读写的隔离级别注解、模板、编程式 begin
TransactionManager事务管理核心接口,提供 begin/commit/rollBack编程式事务、模板内部
TransactionStatus一次事务开启后的状态对象,可标记回滚、只读模板回调、编程式事务
TransactionTemplate用回调包装事务边界局部事务代码
TransactionTemplateManagerTransactionTemplate 的默认实现手动创建模板事务
TransactionHelper从 DataSource 获取事务管理器,或创建注解代理普通 Java 程序
LocalTransactionManager本地事务管理器实现,一个实例绑定一个 DataSource直接创建或由 TransactionHelper 创建

内部结构可以理解为:

DataSource
|
v
LocalTransactionManager -- begin/commit/rollBack --> TransactionStatus
|
+-- TransactionTemplateManager.execute(...)
|
+-- TransactionInterceptor --> @Transactional

深入阅读​