@Transactional
是Spring框架提供的一个关于事务管理的注解,它实现了声明式事务管理。这个注解可以被应用在接口定义、类定义和方法级别。
1.使用@Transactional
通常,我们会在需要进行数据库操作的service层的方法上添加@Transactional注解,来表明该方法需要进行数据库事务控制。以下是一个简单的例子:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void insertTwo() {
User userA = new User();
userA.setUserName("userA");
userRepository.save(userA);
// 制造一个错误,使得两次插入操作都无法成功
int error = 1 / 0;
User userB = new User();
userB.setUserName("userB");
userRepository.save(userB);
}
}
以上代码中,insertTwo
方法内部有两次数据插入操作,如果一次成功一次失败,则两次操作都不会生效,因为它们被包含在同一个事务当中。
2.@Transactional参数详解
-
propagation:定义事务的传播行为,默认值是
Propagation.REQUIRED
。REQUIRED
:如果当前存在事务,那么加入该事务;如果当前没有事务,则创建一个新的事务。SUPPORTS
:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式执行。MANDATORY
:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。REQUIRES_NEW
:创建新的事务,如果当前存在事务,把当前事务挂起。NOT_SUPPORTED
:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。NEVER
:以非事务方式执行,如果当前存在事务,则抛出异常。NESTED
:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则此选项等价于REQUIRED
。
-
isolation:定义事务的隔离级别,默认值是
Isolation.DEFAULT
。DEFAULT
:使用后端数据库默认的隔离级别。READ_UNCOMMITTED
:读取未提交数据。READ_COMMITTED
:读取已提交数据。REPEATABLE_READ
:可重复读。SERIALIZABLE
:串行化。
-
timeout:设置事务超时时间,默认值是
-1
,表示永不超时。 -
readOnly:指定事务是否为只读事务。只读事务可以帮助数据库引擎优化事务。如若事务只读取数据而不做任何更新操作,应设置为只读。
-
rollbackFor:用于指定能引发事务回滚的异常类数组。
-
noRollbackFor:用于指定不会引发事务回滚的异常类数组。
以下是使用了所有参数的示例:
@Transactional(propagation = Propagation.REQUIRED,
isolation = Isolation.READ_COMMITTED,
timeout = 3600,
readOnly = false,
rollbackFor = Exception.class,
noRollbackFor = FileNotFoundException.class)
public void insertTwo() {
// ...
}
3.事务失效的原因
有时候,我们在使用 @Transactional
注解后,会发现事务并没有如预期那样生效。这种情况可能是由以下几个原因导致的:
-
方法访问权限设置问题:被
@Transactional
注解的方法必须是public的。 -
事务方法嵌套调用问题:如果在同一个类中,一个没有使用
@Transactional
的方法内部调用了另一个带有@Transactional
的方法,那么事务是不会起作用的。 -
数据库引擎不支持事务:例如,MySQL的MyISAM引擎就不支持事务。
-
异常类型不匹配:默认情况下,当运行时(unchecked)异常发生时,Spring会标记事务进行回滚;对于检查型(checked)异常,Spring则不会标记事务进行回滚。可以通过
rollbackFor
和noRollbackFor
参数来改变这一行为。
以上就是 @Transactional
的基本使用和事务失效的常见原因。希望能帮助大家更好地理解和使用 @Transactional
来管理你们的事务。
4.总结
使用Transactional注解可以帮我们更简单、方便地进行事务控制。然而,它并不适用于所有场合,比如在多线程环境中,由于Spring采用线程绑定的策略来管理事务,因此@Transactional无效;另外,在异步方法中,@Transactional也无法生效。