@Transactional
1. 介绍
@Transactional
是 Spring 框架提供的一个注解,用于声明方法或类级别的事务属性。
Spring事务:Spring学习笔记_28——事务-****博客
当你在一个方法或类上使用 @Transactional
注解时,Spring 会为该方法或类创建一个事务代理,以确保方法的执行是在事务的上下文中进行的。
2. 场景
@Transactional
注解在 Spring 框架中被广泛用于需要事务管理的业务场景。以下是一些常见的业务场景,其中@Transactional
注解的使用是非常合适的:
-
数据一致性保证:
- 在涉及多个数据库操作,需要保证这些操作要么全部成功,要么全部失败的场景中,使用
@Transactional
可以确保数据的一致性。
- 在涉及多个数据库操作,需要保证这些操作要么全部成功,要么全部失败的场景中,使用
-
并发事务处理:
- 当多个用户或服务同时对同一数据进行操作时,使用
@Transactional
可以防止数据竞争条件和不一致性。
- 当多个用户或服务同时对同一数据进行操作时,使用
-
资金交易:
- 在电子商务或金融应用中,资金转账、支付处理等场景需要精确的事务控制,以确保资金的正确流动。
-
库存管理:
- 在订单处理系统中,库存的增减需要在事务控制下进行,以避免超卖或库存不一致的问题。
-
用户注册和登录:
- 用户注册时创建用户记录和相关配置信息,或者登录时更新用户状态,这些操作需要在事务控制下确保数据的一致性。
-
数据批量处理:
- 在处理批量数据导入或导出时,需要确保所有数据项都成功处理,或者在遇到错误时回滚,以保持数据的完整性。
-
复合操作:
- 当需要执行一系列复合操作,如更新多个相关联的表或记录时,使用
@Transactional
可以确保这些操作作为一个整体被处理。
- 当需要执行一系列复合操作,如更新多个相关联的表或记录时,使用
-
错误恢复:
- 在业务操作中,如果遇到异常需要回滚到操作前的状态,
@Transactional
可以自动处理这种回滚。
- 在业务操作中,如果遇到异常需要回滚到操作前的状态,
-
缓存与数据库同步:
- 当更新数据库的同时需要更新缓存,以保持缓存数据的一致性,
@Transactional
可以确保数据库和缓存的更新操作要么同时成功,要么同时失败。
- 当更新数据库的同时需要更新缓存,以保持缓存数据的一致性,
-
分布式事务:
- 在微服务架构中,跨服务的数据操作可能需要分布式事务来保证数据的一致性。
-
异步消息处理:
- 在处理消息队列中的消息时,可能需要确保消息的发送和数据库操作的一致性。
-
服务层方法:
- 在服务层封装业务逻辑时,如果业务逻辑涉及到多个数据访问操作,使用
@Transactional
可以简化事务管理。
- 在服务层封装业务逻辑时,如果业务逻辑涉及到多个数据访问操作,使用
-
补偿事务:
- 在需要执行补偿操作的场景中,如果一个操作失败,需要执行另一个操作来补偿,
@Transactional
可以确保这两个操作的一致性。
- 在需要执行补偿操作的场景中,如果一个操作失败,需要执行另一个操作来补偿,
3. 源码
/**
* @author Colin Sampaleanu
* @author Juergen Hoeller
* @author Sam Brannen
* @author Mark Paluch
* @since 1.2
* @see org.springframework.transaction.interceptor.TransactionAttribute
* @see org.springframework.transaction.interceptor.DefaultTransactionAttribute
* @see org.springframework.transaction.interceptor.RuleBasedTransactionAttribute
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Reflective
public @interface Transactional {
// String类型,用以指定事务管理器的唯一标识
@AliasFor("transactionManager")
String value() default "";
/**
* @since 4.2
*/
// 用以指定事务管理器的唯一标识
@AliasFor("value")
String transactionManager() default "";
/**
* @since 5.3
*/
// 设置属性的标签
String[] label() default {};
// Propagation枚举类型的属性,指定事务的隔离级别
Propagation propagation() default Propagation.REQUIRED;
// isolation枚举类型的属性,指定事务隔离的级别,
Isolation isolation() default Isolation.DEFAULT;
// timeout指定事务的超时时间,单位为秒,当事务执行时间超过timeout秒时,就会触发超时回滚操作,并释放事务占用的资源
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
/**
* @since 5.3
*/
// 以String类型设置超时时间,单位为秒
String timeoutString() default "";
// 指定是否为只读事务
// ture:只读
// false:非只读
boolean readOnly() default false;
// 指定异常类的Class对象,当抛出指定类型异常或者其子类型的异常时,事务会自动回滚
Class<? extends Throwable>[] rollbackFor() default {};
// 指定异常类的全类名,当抛出指定全类名的异常或者其子类型的异常时,事务自动回滚
String[] rollbackForClassName() default {};
// 指定异常类的class对象,当抛出指定类型的异常或者其子类型的异常时,事务不会自动回滚
Class<? extends Throwable>[] noRollbackFor() default {};
// 指定异常类的全类名,当抛出指定全类名的异常或者其子类型的异常时,事务不会自动回滚
String[] noRollbackForClassName() default {};
}
4. Demo
- 不同传播行为
@Transactional(propagation = Propagation.REQUIRED)
public void updateProductStock(Long productId, int quantity) {
// 业务逻辑:更新产品库存
}
- 不同隔离级别
@Transactional(isolation = Isolation.READ_COMMITTED)
public void processOrder(Long orderId) {
// 以 READ_COMMITTED 隔离级别执行的业务逻辑
}
- 超时时间
@Transactional(timeout = 5) // 超时时间设置为5秒
public void longRunningProcess() {
// 长时间运行的业务逻辑
}
- 只读事务
@Transactional(readOnly = true)
public List<Product> getAllProducts() {
// 只读事务,用于查询所有产品的列表
}
- 设置回滚异常
@Transactional(rollbackFor = Exception.class) // 默认所有异常都会触发回滚
public void processWithCustomRollback(Long productId) {
// 如果抛出Exception类型的异常,事务将回滚
}
@Transactional(noRollbackFor = ArithmeticException.class)
public void processWithNoRollback(Long productId) {
// 如果抛出ArithmeticException类型的异常,事务不会回滚
}
- 组合应用
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.SERIALIZABLE, timeout = 10, readOnly = false, rollbackFor = Exception.class)
public void complexBusinessProcess(Long productId, int quantity) {
// 组合使用不同的@Transactional参数
// 这个操作将在一个新的事务中执行,具有SERIALIZABLE隔离级别,超时时间为10秒,非只读事务,并且所有异常都会触发回滚
}