@Transactional
是 Spring 框架提供的一个注解,用于声明一个方法或类需要在事务的上下文中执行。当标注在方法上时,表示该方法执行期间使用事务;当标注在类上时,表示该类中的所有公共方法都将使用事务。
Spring 使用 AOP(面向切面编程)来在运行时动态地代理对象,并在调用标注了 @Transactional
的方法时,自动地开启、提交或回滚事务。
主要特性:
-
传播行为:通过
propagation
属性,你可以定义事务如何传播。例如,Propagation.REQUIRED
表示当前方法必须在一个事务中运行,如果当前没有事务,就新建一个事务。 -
隔离级别:通过
isolation
属性,你可以设置事务的隔离级别,以避免多个事务之间的脏读、不可重复读、幻读等问题。 -
只读标志:
readOnly
属性允许你将事务标记为只读,这样数据库引擎就可以针对只读事务进行优化。 -
超时设置:
timeout
属性允许你设置事务的超时时间,超过这个时间后,事务将被自动回滚。 -
回滚规则:默认情况下,如果在事务中抛出了未检查的异常(通常是运行时异常),事务将回滚。但是,你可以通过
rollbackFor
和noRollbackFor
属性来定制回滚规则。
示例:
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void createUser(User user) {
userRepository.save(user);
// 其他数据库操作...
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void createUserInNewTransaction(User user) {
// 将在新的事务中执行
userRepository.save(user);
}
}
在上面的例子中,createUser
方法被标记为 @Transactional
,因此当它被调用时,Spring 会确保在一个事务的上下文中执行该方法内的所有数据库操作。如果 createUser
方法中抛出运行时异常,Spring 会自动回滚事务。
createUserInNewTransaction
方法使用了 propagation = Propagation.REQUIRES_NEW
,这意味着它总是会在一个新的事务中执行,即使它被另一个已经在事务中的方法调用。
注意事项:
- 确保
@Transactional
注解应用在公共方法上,因为 Spring AOP 默认只代理公共方法。 @Transactional
注解不会阻止异常传播到调用者。如果你的方法抛出了异常,调用者仍然需要处理它。- 如果你的方法内部调用了同一个类的另一个
@Transactional
方法,Spring 的默认代理机制不会工作,因为调用是在同一个对象内部进行的,而不是通过代理。这种情况下,你需要将内部方法调用重构为通过 Spring 容器获取的代理对象来调用,或者使用AopContext.currentProxy()
来获取当前代理对象的引用。 - 默认情况下,
@Transactional
注解只能用于 public 方法。如果你需要在 protected、private 或默认访问级别的方法上使用事务,你可能需要配置 Spring AOP 来支持这些访问级别的方法。 @Transactional 一般用在 Service 层代码中。