从细节处了解Spring中@Transactional注解失效的常见场景
2023-05-04 06:05:53
7 种常见场景会导致 @Transactional 注解失效
在使用 Spring 框架进行事务管理时,@Transactional 注解是必不可少的工具。它允许我们轻松地定义事务边界,确保数据操作要么完全成功,要么完全回滚。然而,在某些情况下,@Transactional 注解可能不起作用,导致事务失效。本文将探讨这 7 种常见的场景,帮助你避免这些陷阱,确保你的事务管理始终如一。
1. @Transactional 应用在非 public 方法上
@Transactional 注解只能应用在 public 方法上。如果应用在 protected、private 或 default 方法上,则该注解不会起作用,事务也不会生效。
示例:
@Transactional
private void doSomething() {
// 事务不会生效
}
2. 方法抛出 unchecked 异常
如果方法抛出 unchecked 异常,例如 NullPointerException 或 ArrayIndexOutOfBoundsException,则事务也会失效。这是因为 unchecked 异常不会导致方法被回滚,而 @Transactional 注解默认情况下只会回滚 checked 异常。
示例:
@Transactional
public void doSomething() {
throw new NullPointerException();
// 事务不会回滚
}
3. 方法中调用了带有 @Transactional(propagation = Propagation.REQUIRES_NEW) 注解的方法
如果方法中调用了带有 @Transactional(propagation = Propagation.REQUIRES_NEW) 注解的方法,则新方法将开启一个新的事务,而旧方法的事务将被挂起。如果新方法执行成功,则两个事务都会提交;如果新方法执行失败,则两个事务都会回滚。
示例:
@Transactional
public void doSomething() {
doSomethingElse();
// 如果 doSomethingElse() 执行失败,两个事务都会回滚
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void doSomethingElse() {
throw new RuntimeException();
}
4. 方法中调用了带有 @Transactional(readOnly = true) 注解的方法
如果方法中调用了带有 @Transactional(readOnly = true) 注解的方法,则该方法将以只读方式执行,并且不会开启事务。
示例:
@Transactional
public void doSomething() {
findSomething();
// 不开启事务,不会执行任何更新
}
@Transactional(readOnly = true)
public void findSomething() {
// 只读操作
}
5. 方法中调用了带有 @Transactional(noRollbackFor = Exception.class) 注解的方法
如果方法中调用了带有 @Transactional(noRollbackFor = Exception.class) 注解的方法,则该方法将不会对指定的异常进行回滚。
示例:
@Transactional
public void doSomething() {
try {
doSomethingElse();
} catch (Exception e) {
// 事务不会回滚
}
}
@Transactional(noRollbackFor = Exception.class)
public void doSomethingElse() {
throw new RuntimeException();
}
6. 方法中调用了本地方法或使用了本地代码
如果方法中调用了本地方法或使用了本地代码,则事务也可能失效。这是因为本地代码不受 Java 虚拟机的管理,因此它可以绕过事务机制。
示例:
@Transactional
public void doSomething() {
System.loadLibrary("native-library");
// 本地代码不受事务管理
}
7. 使用了 Spring 的声明式事务管理,但没有配置事务管理器
如果使用了 Spring 的声明式事务管理,但没有配置事务管理器,则 @Transactional 注解也不会起作用。这是因为事务管理器是事务管理的关键组件,它负责创建和管理事务。
示例:
<!-- 没有配置事务管理器 -->
<bean id="myService" class="com.example.MyService" />
结论
了解和避免这些会导致 @Transactional 注解失效的常见场景至关重要。通过谨慎地应用这些注解,你可以确保你的事务管理始终如一,避免意外的数据损坏或丢失。
常见问题解答
-
如果方法抛出了 checked 异常,事务总是会被回滚吗?
- 不一定。如果 @Transactional 注解的 rollbackFor 属性设置为 false,则事务将不会回滚。
-
@Transactional 注解可以应用在接口方法上吗?
- 不可以。@Transactional 注解只能应用在实现类的方法上。
-
如果在方法中嵌套调用了多个带有 @Transactional 注解的方法,会发生什么?
- 嵌套的事务将与外层事务使用相同的传播行为。
-
如何禁用事务?
- 可以通过将 @Transactional 注解的 value 属性设置为 "PROPAGATION_NEVER" 或 "PROPAGATION_NOT_SUPPORTED" 来禁用事务。
-
如果事务管理器配置了多个数据源,会发生什么?
- 默认情况下,@Transactional 注解将使用默认数据源。可以通过指定 dataSource 属性来覆盖此设置。