目录
- 前言
- 1. 基本知识
- 2. 常用属性
- 3. Demo
- 4. 总结
前言
@Transactional
是 Spring 框架中用于管理事务的注解。
-
该注解来源于Spring,对于Spring的基础知识可看我之前的文章:
Spring框架从入门到学精(全) -
该注解也可用在xxl-job框架中,让事务进行回滚执行,可看我之前的文章:
详细分析Java中的分布式任务调度框架 XXL-Job -
涉及的事务相关知识可参考之前这篇文章:
数据库关于事务的详解分析(全)包含面试常问的细节
1. 基本知识
@Transactional
注解用于标记一个方法或类需要被 Spring 托管的事务管理。
它可以应用于类级别的和方法级别的,用于控制事务的行为。
作用 | 优点 | 缺点 |
---|---|---|
1.事务管理 : 该注解确保被注解的方法或类在执行时将被包装在一个事务中。2. 事务传播 : 它定义了在嵌套调用中,新事务是如何与现有事务交互的。 | 1.简化事务管理 : 通过注解方式,简化了对事务的管理,不再需要手动编写事务相关的代码。2. 减少样板代码 : 提供了一种声明式的方式,减少了样板式的事务管理代码。 | 过度使用可能导致性能问题: 在某些情况下,过度使用事务注解可能导致性能下降,因为每个被注解的方法都会被包装在一个事务中。 |
对于@Transactional
注解有好些属性,可通过源码查看:
2. 常用属性
常用的属性主要如下:
一、propagation: 事务的传播行为,默认值是 REQUIRED
。
常用的取值包括:
REQUIRED
:如果当前存在事务,则加入该事务;否则,创建一个新事务。REQUIRES_NEW
:创建一个新的事务,并挂起当前事务(如果存在)。SUPPORTS
:支持当前事务,如果没有事务,则以非事务方式执行。MANDATORY
:强制要求存在当前事务,如果不存在,则抛出异常
示例代码如下:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodWithNewTransaction() {// ...
}
二、isolation: 事务的隔离级别,默认是 DEFAULT
。
常用的取值包括:
DEFAULT
:使用数据库默认的隔离级别。READ_UNCOMMITTED
:允许读取未提交的数据更改。READ_COMMITTED
:只能读取已提交的数据更改。REPEATABLE_READ
:可重复读,确保在同一事务中对相同数据的多次读取是一致的。SERIALIZABLE
:最高隔离级别,确保在同一事务中对相同数据的多次读取和写入都是一致的。
示例代码如下:
@Transactional(isolation = Isolation.READ_COMMITTED)
public void methodWithCustomIsolationLevel() {// ...
}
三、readOnly: 指定事务是否为只读,默认值为 false。
如果设置为 true,表示只读事务,不允许有写操作。
@Transactional(readOnly = true)
public void readOnlyMethod() {// ...
}
四、timeout: 指定事务超时时间,单位为秒。
如果事务执行时间超过设定的超时时间,将回滚事务。
@Transactional(timeout = 30)
public void methodWithTimeout() {// ...
}
五、rollbackFor 和 noRollbackFor: 指定在哪些异常情况下回滚事务或不回滚事务。
@Transactional(rollbackFor = CustomException.class)
public void methodWithRollbackForException() {// ...
}@Transactional(noRollbackFor = AnotherException.class)
public void methodWithNoRollbackForException() {// ...
}
这些是 @Transactional
注解中一些常用的属性。通过设置这些属性,你可以根据具体需求调整事务的行为。
3. Demo
假设有一个简单的银行应用,有两个服务类,一个是转账服务 TransferService,另一个是用户服务 UserService。
确保转账和更新用户余额这两个操作在同一个事务中。
代码如下:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class TransferService {@Autowiredprivate UserService userService;@Transactionalpublic void transferMoney(String fromAccount, String toAccount, double amount) {// 扣除转账账户余额userService.decreaseBalance(fromAccount, amount);// 增加接收账户余额userService.increaseBalance(toAccount, amount);}
}
以及
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class UserService {@Autowiredprivate JdbcTemplate jdbcTemplate;@Transactionalpublic void decreaseBalance(String account, double amount) {// 扣除余额的数据库更新操作// ...}@Transactionalpublic void increaseBalance(String account, double amount) {// 增加余额的数据库更新操作// ...}
}
在上述示例中,@Transactional
注解确保了 transferMoney 方法和 decreaseBalance、increaseBalance 方法都在同一个事务中执行。
如果其中任何一个方法发生异常,整个事务将回滚。
对于实际的应用场景,一个rollbackFor也可:@Transactional(rollbackFor = Exception.class)
具体如下:
也可配合XXL-Job的框架进行使用,主要如下:
4. 总结
对应的场景案例可看这篇文章(个人感觉不错):spring中@Transactional注解的作用,使用场景举例
@Transactional
注解只能用在public 方法上,private以及protected不会报错,但不会生效- 该注解只有在spring容器中扫描到才生效
- 可以用在类上或者方法上,范围不一致而已
- 如果使用了try catch,注解会失效。(虽然只能回滚非检查型异常,具体为RuntimeException及其子类和Error子类,但要想捕获可以尝试加入
@Transactional(rollbackFor = Exception.class)
) - 非事务方法调用事务方法,要用代理对象调用否则事务会失效。而事务方法调用非事务不会失效。