在企业级应用开发中,事务管理是确保数据一致性和业务完整性的关键技术。Spring框架提供了一套完整的事务管理抽象,让开发者能够以声明式的方式处理事务,而无需直接操作底层API。
事务具有ACID四大特性:
与传统JDBC事务管理相比,Spring事务管理具有以下优势:
Spring事务管理的核心接口是PlatformTransactionManager,它为不同的事务API提供了统一的抽象:
java复制public interface PlatformTransactionManager {
TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
Spring支持多种事务管理器实现,常见的有:
| 事务管理器 | 适用场景 | 配置示例 |
|---|---|---|
| DataSourceTransactionManager | 单个数据源JDBC事务 | @Bean DataSourceTransactionManager |
| JpaTransactionManager | JPA/Hibernate事务 | @Bean JpaTransactionManager |
| JtaTransactionManager | 分布式事务(JTA) | @Bean JtaTransactionManager |
| HibernateTransactionManager | Hibernate特定事务 | @Bean HibernateTransactionManager |
TransactionDefinition接口定义了事务的基本属性:
java复制public interface TransactionDefinition {
int getPropagationBehavior(); // 传播行为
int getIsolationLevel(); // 隔离级别
int getTimeout(); // 超时时间(秒)
boolean isReadOnly(); // 是否只读
String getName(); // 事务名称
}
@Transactional是Spring声明式事务的核心注解,主要属性包括:
java复制@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
String value() default "";
String transactionManager() default "";
Propagation propagation() default Propagation.REQUIRED;
Isolation isolation() default Isolation.DEFAULT;
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
boolean readOnly() default false;
Class<? extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
}
Spring支持三种配置声明式事务的方式:
xml复制<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="serviceOperation"
expression="execution(* com.example.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation"/>
</aop:config>
java复制@Configuration
@EnableTransactionManagement
public class AppConfig {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
java复制@Service
public class UserService {
@Transactional
public void createUser(User user) {
// 业务逻辑
}
}
Spring定义了7种事务传播行为:
| 传播行为 | 说明 |
|---|---|
| REQUIRED | 支持当前事务,如果不存在则新建一个(默认) |
| SUPPORTS | 支持当前事务,如果不存在则以非事务方式执行 |
| MANDATORY | 支持当前事务,如果不存在则抛出异常 |
| REQUIRES_NEW | 新建事务,如果存在当前事务则挂起 |
| NOT_SUPPORTED | 以非事务方式执行,如果存在当前事务则挂起 |
| NEVER | 以非事务方式执行,如果存在事务则抛出异常 |
| NESTED | 如果存在当前事务,则在嵌套事务中执行 |
java复制@Service
public class OrderService {
@Transactional(propagation = Propagation.REQUIRED)
public void createOrder(Order order) {
// 主业务逻辑
processOrder(order);
try {
// 需要独立事务的操作
auditService.logOperation(order);
} catch (Exception e) {
// 审计日志失败不影响主业务
log.error("审计日志记录失败", e);
}
}
}
@Service
class AuditService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logOperation(Order order) {
// 独立事务记录审计日志
auditRepository.save(new AuditLog(order));
}
}
| 问题 | 描述 | 解决方案 |
|---|---|---|
| 脏读 | 读取到其他事务未提交的数据 | 提高隔离级别 |
| 不可重复读 | 同一事务内多次读取结果不一致 | 使用可重复读隔离级别 |
| 幻读 | 同一查询条件返回不同的行数 | 使用串行化隔离级别 |
Spring支持5种隔离级别:
java复制public enum Isolation {
DEFAULT(TransactionDefinition.ISOLATION_DEFAULT), // 使用数据库默认
READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED),
READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED),
REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ),
SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE)
}
java复制@Service
public class UserService {
@Autowired
private UserService self; // 注入自身代理
public void updateUser(User user) {
// 通过代理调用
self.doUpdate(user);
}
@Transactional
public void doUpdate(User user) {
// 事务操作
}
}
java复制@Transactional(rollbackFor = Exception.class)
public void saveWithException() throws Exception {
try {
userRepository.save(new User());
throw new Exception("测试异常");
} catch (Exception e) {
log.error("保存失败", e);
throw e; // 重新抛出异常
}
}
java复制@Service
public class OrderService {
@Autowired
private TransactionTemplate transactionTemplate;
public void processOrder(Order order) {
transactionTemplate.execute(status -> {
try {
// 业务逻辑
inventoryService.reduceStock(order);
orderRepository.save(order);
return true;
} catch (Exception e) {
status.setRollbackOnly();
throw e;
}
});
}
}
java复制@Service
public class AccountService {
@Autowired
private PlatformTransactionManager transactionManager;
public void transfer(Account from, Account to, BigDecimal amount) {
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
definition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
definition.setTimeout(30);
TransactionStatus status = transactionManager.getTransaction(definition);
try {
from.debit(amount);
to.credit(amount);
accountRepository.save(from);
accountRepository.save(to);
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
throw e;
}
}
}
java复制@Configuration
@EnableTransactionManagement
public class JtaConfig {
@Bean
public JtaTransactionManager transactionManager() {
UserTransactionManager utm = new UserTransactionManager();
UserTransaction ut = new UserTransactionImp();
return new JtaTransactionManager(ut, utm);
}
@Bean
public DataSource dataSource1() {
AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
// 配置数据源1
return ds;
}
@Bean
public DataSource dataSource2() {
AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
// 配置数据源2
return ds;
}
}
java复制@Configuration
public class MultiDataSourceConfig {
@Primary
@Bean
@ConfigurationProperties("spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
@Primary
@Bean
public PlatformTransactionManager primaryTxManager(DataSource primaryDataSource) {
return new DataSourceTransactionManager(primaryDataSource);
}
@Bean
public PlatformTransactionManager secondaryTxManager(DataSource secondaryDataSource) {
return new DataSourceTransactionManager(secondaryDataSource);
}
@Bean
public ChainedTransactionManager chainedTransactionManager(
PlatformTransactionManager primary,
PlatformTransactionManager secondary) {
return new ChainedTransactionManager(primary, secondary);
}
}
Spring事务基于AOP实现,核心流程如下:
Spring使用TransactionSynchronizationManager管理事务上下文,通过ThreadLocal实现线程隔离:
java复制public abstract class TransactionSynchronizationManager {
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<>("Transaction synchronizations");
private static final ThreadLocal<String> currentTransactionName =
new NamedThreadLocal<>("Current transaction name");
// 其他状态...
}
java复制@Aspect
@Component
@Slf4j
public class TransactionMonitor {
@Around("@annotation(org.springframework.transaction.annotation.Transactional)")
public Object monitor(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
String method = joinPoint.getSignature().toShortString();
try {
Object result = joinPoint.proceed();
log.info("事务成功 - {} 耗时: {}ms", method,
System.currentTimeMillis() - start);
return result;
} catch (Exception e) {
log.error("事务回滚 - {} 耗时: {}ms 原因: {}", method,
System.currentTimeMillis() - start, e.getMessage());
throw e;
}
}
}
java复制@Service
@Transactional
public class OrderServiceImpl implements OrderService {
@Autowired
private InventoryService inventoryService;
@Autowired
private PaymentService paymentService;
public Order createOrder(OrderRequest request) {
// 1. 扣减库存
inventoryService.reduceStock(request.getSkuId(), request.getQuantity());
// 2. 创建订单
Order order = new Order(request);
orderRepository.save(order);
// 3. 支付
PaymentResult result = paymentService.process(order);
if (!result.isSuccess()) {
throw new PaymentException("支付失败");
}
// 4. 更新订单状态
order.paid();
return orderRepository.save(order);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void cancelOrder(Long orderId) {
Order order = orderRepository.findById(orderId)
.orElseThrow(OrderNotFoundException::new);
// 恢复库存
inventoryService.restoreStock(order.getSkuId(), order.getQuantity());
// 更新订单状态
order.cancel();
orderRepository.save(order);
}
}
java复制@Service
public class AccountServiceImpl implements AccountService {
@Transactional(isolation = Isolation.SERIALIZABLE, timeout = 30)
public void transfer(Long fromId, Long toId, BigDecimal amount) {
Account from = accountRepository.findAndLockById(fromId);
Account to = accountRepository.findAndLockById(toId);
// 验证余额
if (from.getBalance().compareTo(amount) < 0) {
throw new InsufficientBalanceException();
}
// 执行转账
from.debit(amount);
to.credit(amount);
// 保存账户
accountRepository.save(from);
accountRepository.save(to);
// 记录交易
Transaction tx = new Transaction(from, to, amount);
transactionRepository.save(tx);
}
}
Spring Boot通过TransactionAutoConfiguration自动配置事务管理器:
yaml复制spring:
transaction:
default-timeout: 30
rollback-on-commit-failure: true
datasource:
hikari:
auto-commit: false
jpa:
properties:
javax.persistence.lock.timeout: 10000
javax.persistence.query.timeout: 5000
在实际项目中,我曾遇到一个典型的自调用导致事务失效的问题。服务类中的一个public方法调用了本类的另一个@Transactional方法,由于Spring AOP代理机制的限制,事务注解没有生效。通过注入自身代理解决后,事务行为恢复正常。这个案例让我深刻理解了Spring事务实现的原理和使用时的注意事项。