Spring中@Transactional注解
在Spring框架中,@Transactional
是一个注解,用于声明事务性的方法。这个注解可以被应用在方法级别或类级别上。它提供了一种声明式的事务管理方式,避免了在代码中直接编写事务管理相关的代码。@Transactional
注解能够将一个方法纳入到一个事务中,使其成为一个事务性方法。
以下是 @Transactional
注解的一些关键属性和用法:
关键属性和用法
1. Propagation(传播行为):
- 定义了事务方法的执行期间,当前事务传播到被调用的方法。
- 常用的传播行为包括
REQUIRED
(如果有事务,则加入;没有事务,则新建一个)和REQUIRES_NEW
(每次都新建一个事务,挂起当前事务)。
@Transactional(propagation = Propagation.REQUIRED)
public void transactionalMethod() {
// 方法体
}
2. Isolation(隔离级别):
- 定义了事务的隔离级别,即多个事务并发执行时,事务之间的隔离程度。
- 常用的隔离级别包括
READ_COMMITTED
(允许读取已提交的数据,避免脏读)和SERIALIZABLE
(最高的隔离级别,保证事务的完全隔离)。
@Transactional(isolation = Isolation.READ_COMMITTED)
public void transactionalMethod() {
// 方法体
}
3. ReadOnly(只读):
- 指定事务是否为只读事务。如果设置为
true
,则表示这个事务只读取数据但不更新数据,可以提高事务的性能。
@Transactional(readOnly = true)
public void readOnlyTransactionalMethod() {
// 方法体
}
4. Timeout(超时):
- 定义了事务的超时时间,即事务方法的执行时间超过了这个值,事务将被回滚。
@Transactional(timeout = 60) // 60 秒超时
public void transactionalMethod() {
// 方法体
}
5. RollbackFor(回滚异常):
- 指定哪些异常触发事务回滚。可以指定多个异常类型。
@Transactional(rollbackFor = {SQLException.class, IOException.class})
public void transactionalMethod() throws SQLException, IOException {
// 方法体
}
6. NoRollbackFor(不回滚异常):
- 指定哪些异常不触发事务回滚。同样可以指定多个异常类型。
@Transactional(noRollbackFor = BusinessException.class)
public void transactionalMethod() throws BusinessException {
// 方法体
}
使用方法:
-
在类级别使用
@Transactional
:@Service @Transactional public class MyService { // 方法 }
-
在方法级别使用
@Transactional
:@Service public class MyService { @Transactional public void myTransactionalMethod() { // 方法体 } }
事务回滚
事务回滚是指在事务执行过程中发生了某些错误或异常,系统会撤销当前事务的所有操作,使数据回滚到事务开始之前的状态。
事务回滚的作用是确保事务的一致性和完整性。如果在事务中发生了错误,事务回滚可以防止数据的部分更新,确保数据库的一致性。
何时会触发事务回滚:
-
Unchecked 异常: 默认情况下,Spring
@Transactional
注解只会在遇到未检查(unchecked)异常时触发事务回滚。未检查异常是指继承自RuntimeException
的异常,如NullPointerException
、ArithmeticException
等。@Transactional public void transactionalMethod() { // 发生未检查异常时,事务将回滚 throw new RuntimeException("Something went wrong"); }
-
指定回滚条件: 通过
rollbackFor
或noRollbackFor
属性,可以在@Transactional
注解上指定哪些异常触发事务回滚或不触发事务回滚。@Transactional(rollbackFor = {SQLException.class, IOException.class}) public void transactionalMethod() throws SQLException, IOException { // 发生指定异常时,事务将回滚 throw new SQLException("Database error"); }
-
Checked 异常: 如果需要回滚事务的是受检查的异常(checked exception),可以使用
@Transactional(rollbackFor = Exception.class)
,但这并不是通常的做法,因为通常情况下事务回滚更关注未检查异常。
@Transactional(rollbackFor = Exception.class)
表示在使用 Spring 的声明式事务管理时,如果发生任何Exception
及其子类的异常,都会导致事务回滚。这意味着如果在被注解的方法中抛出了任何Exception
,不管是 checked 还是 unchecked 异常,都会触发事务回滚。- 这种设置的意义在于,有时候我们可能希望对于某些异常情况,即便是 checked 异常,也触发事务回滚。通常情况下,Spring 默认只对未检查异常(
RuntimeException
及其子类)进行回滚。通过设置rollbackFor = Exception.class
,我们扩大了回滚的范围,即使是 checked 异常也会导致事务回滚。
例子:
@Transactional(rollbackFor = Exception.class)
public void transactionalMethod() throws CustomCheckedException {
// 操作数据库
// 抛出 checked 异常,事务将回滚
throw new CustomCheckedException("Custom checked exception");
}
在上述例子中,即使 CustomCheckedException
是一个 checked 异常,由于设置了 rollbackFor = Exception.class
,这个方法抛出的异常也会导致事务回滚。
需要注意的是,过度使用这样的设置可能会导致意外的结果,因为某些 checked 异常可能是可以被业务逻辑处理的。因此,一般来说,建议在 rollbackFor
中指定具体的异常类型,而不是将其设置为 Exception.class
。
回滚的意义:
- 一致性: 在事务中的一组操作,要么全部执行,要么全部不执行。回滚确保了数据的一致性。
- 完整性: 回滚可以防止数据的部分更新,保证了数据库的完整性。
- 可靠性: 当出现异常或错误时,回滚确保了系统的可靠性,避免了数据不一致或丢失。
与 try-catch 的关系:
在事务性方法中,通常不需要显式地使用 try-catch 块来捕获异常,因为 Spring 会在检测到未检查异常时触发事务回滚。如果在事务性方法中使用了 try-catch 块,并成功捕获了异常,Spring 将不会触发事务回滚。在这种情况下,你可以手动调用 setRollbackOnly
方法来指示事务回滚。
@Transactional
public void transactionalMethod() {
try {
// 操作数据库
} catch (Exception e) {
// 捕获异常,不触发事务回滚
// 手动指示事务回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
@Transactional 没有抛出异常时是否管用:
如果 @Transactional
注解所标注的方法没有抛出未检查异常,并且方法成功完成,那么事务会正常提交,而不会回滚。@Transactional
不仅用于处理异常,还用于确保事务的一致性,即一组操作要么全部成功,要么全部失败。在没有异常抛出的情况下,@Transactional
也能够确保事务的完整性。