声明式事务与编程式事务
Spring提供两种事务管理方式:声明式和编程式。
两种方式对比
| 特性 | 声明式事务 | 编程式事务 |
|---|---|---|
| 实现方式 | @Transactional注解 | TransactionTemplate或PlatformTransactionManager |
| 代码侵入 | 无 | 有 |
| 灵活性 | 较低 | 较高 |
| 细粒度控制 | 方法级别 | 代码块级别 |
| 可读性 | 高 | 一般 |
| 维护成本 | 低 | 较高 |
声明式事务
注解方式
Java
@Service
public class OrderService {
@Transactional
public void createOrder(Order order) {
orderDao.insert(order);
inventoryService.decrease(order.getProductId());
}
@Transactional(readOnly = true)
public Order getOrder(Long id) {
return orderDao.findById(id);
}
@Transactional(rollbackFor = Exception.class)
public void batchImport(List<Order> orders) throws Exception {
for (Order order : orders) {
orderDao.insert(order);
}
}
}
XML配置方式
XML
<!-- 事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="get*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- AOP配置 -->
<aop:config>
<aop:advisor advice-ref="txAdvice"
pointcut="execution(* com.example.service.*.*(..))"/>
</aop:config>
启用事务注解
Java
@Configuration
@EnableTransactionManagement // 启用注解事务
public class AppConfig {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
Spring Boot项目无需此配置,自动配置事务管理器。
编程式事务
TransactionTemplate方式(推荐)
Java
@Service
public class PaymentService {
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
private AccountDao accountDao;
// 无返回值事务
public void transfer(Long fromId, Long toId, BigDecimal amount) {
transactionTemplate.executeWithoutResult(status -> {
try {
accountDao.decrease(fromId, amount);
accountDao.increase(toId, amount);
} catch (Exception e) {
status.setRollbackOnly();
throw e;
}
});
}
// 有返回值事务
public Long createAccount(String name, BigDecimal balance) {
return transactionTemplate.execute(status -> {
Account account = new Account(name, balance);
accountDao.insert(account);
return account.getId();
});
}
// 自定义事务属性
public void customTransaction() {
transactionTemplate.setPropagationBehavior(
TransactionDefinition.PROPAGATION_REQUIRES_NEW);
transactionTemplate.setIsolationLevel(
TransactionDefinition.ISOLATION_READ_COMMITTED);
transactionTemplate.setTimeout(30);
transactionTemplate.executeWithoutResult(status -> {
// 业务逻辑
});
}
}
PlatformTransactionManager方式
Java
@Service
public class ManualTxService {
@Autowired
private PlatformTransactionManager transactionManager;
@Autowired
private OrderDao orderDao;
public void manualControl() {
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
definition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
definition.setTimeout(30);
TransactionStatus status = transactionManager.getTransaction(definition);
try {
orderDao.insert(new Order());
// 根据条件决定提交或回滚
if (someCondition()) {
transactionManager.commit(status);
} else {
transactionManager.rollback(status);
}
} catch (Exception e) {
transactionManager.rollback(status);
throw e;
}
}
}
使用场景选择
声明式事务适用场景
Java
// 场景1:常规CRUD操作
@Service
public class UserService {
@Transactional
public void save(User user) {
userDao.save(user);
}
@Transactional(readOnly = true)
public User findById(Long id) {
return userDao.findById(id);
}
}
// 场景2:标准业务流程
@Service
public class OrderService {
@Transactional
public void createOrder(OrderRequest request) {
Order order = buildOrder(request);
orderDao.insert(order);
inventoryService.decrease(request.getProductId(), request.getQuantity());
paymentService.charge(request.getPayment());
}
}
编程式事务适用场景
Java
// 场景1:细粒度控制
@Service
public class ImportService {
@Autowired
private TransactionTemplate transactionTemplate;
public ImportResult batchImport(List<Data> dataList) {
int success = 0, failed = 0;
for (Data data : dataList) {
// 每条数据独立事务
try {
transactionTemplate.executeWithoutResult(status -> {
dataDao.insert(data);
relatedDao.insert(data.getRelated());
});
success++;
} catch (Exception e) {
failed++;
// 单条失败不影响其他
}
}
return new ImportResult(success, failed);
}
}
// 场景2:条件性回滚
@Service
public class ConditionService {
public void process(Order order) {
transactionTemplate.executeWithoutResult(status -> {
orderDao.insert(order);
if (needRollback(order)) {
status.setRollbackOnly(); // 手动回滚
return;
}
notificationService.send(order);
});
}
}
// 场景3:嵌套事务控制
@Service
public class NestedService {
public void nestedProcess() {
transactionTemplate.executeWithoutResult(outer -> {
outerDao.doSomething();
// 内层独立事务
TransactionTemplate innerTx = new TransactionTemplate(transactionManager);
innerTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
innerTx.executeWithoutResult(inner -> {
innerDao.doSomething();
});
});
}
}
混合使用
Java
@Service
public class MixedService {
@Autowired
private TransactionTemplate transactionTemplate;
// 声明式事务
@Transactional
public void declarativeMethod() {
// 自动事务管理
}
// 编程式事务
public void programmaticMethod() {
transactionTemplate.executeWithoutResult(status -> {
// 手动事务控制
});
}
// 在声明式事务中使用编程式事务(创建新事务)
@Transactional
public void mixed() {
// 外层事务
outerOperation();
// 内层独立事务
TransactionTemplate newTx = new TransactionTemplate(transactionManager);
newTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
newTx.executeWithoutResult(status -> {
// 独立事务,外层回滚不影响此处
logService.saveLog();
});
}
}
最佳实践
| 场景 | 推荐方式 | 原因 |
|---|---|---|
| 常规业务方法 | 声明式 | 简洁、可读性好 |
| 批量处理部分失败 | 编程式 | 细粒度控制 |
| 条件性回滚 | 编程式 | 灵活控制 |
| 需要事务内独立事务 | 编程式 | 精确控制传播 |
| 团队协作项目 | 声明式 | 统一风格 |
要点总结
- 声明式事务通过@Transactional实现,代码简洁
- 编程式事务通过TransactionTemplate实现,控制灵活
- 声明式适合大多数常规场景
- 编程式适合需要细粒度控制的特殊场景
- TransactionTemplate比直接使用PlatformTransactionManager更简洁
- 同一类中可混合使用两种方式
📝 发现内容有误?点击此处直接编辑