我们来一步步详细讲解。
简介
在Spring中,@Transactional
注解可以用于标注事务处理的方法,其中isolation
和propagation
两个属性用来设置事务的隔离级别和传播特性。本文将主要围绕这两个属性展开讲解。
隔离级别
事务隔离级别是解决数据库并发访问引发的一系列问题的标准。Spring框架提供了五种不同的隔离级别,分别是:
ISOLATION_DEFAULT
:采用默认的数据库隔离级别。ISOLATION_READ_UNCOMMITTED
:读取未提交的数据,该隔离级别存在数据不一致的问题。ISOLATION_READ_COMMITTED
:读取已提交的数据,可以避免脏读问题。ISOLATION_REPEATABLE_READ
:可以多次读取同一件事物的数据,可以防止脏读和不可重复的读问题。ISOLATION_SERIALIZABLE
:最高的隔离级别,可以防止脏读、不可重复的读和幻读问题。
传播特性
在Spring框架中,一个事务方法内部还可以调用其他事务方法,这时就需要使用传播特性来控制事务的传播方式。Spring提供了7种传播特性,分别是:
PROPAGATION_REQUIRED
:如果当前存在一个事务,则加入该事务,否则创建一个新事务。PROPAGATION_SUPPORTS
:如果当前存在一个事务,则加入该事务,否则按非事务方式执行。PROPAGATION_MANDATORY
:如果当前存在一个事务,则加入该事务,否则抛出异常。PROPAGATION_REQUIRES_NEW
:创建一个新的事务,如果当前存在事务,则将当前事务挂起。PROPAGATION_NOT_SUPPORTED
:以非事务方式执行操作,如果当前存在事务,则将当前事务挂起。PROPAGATION_NEVER
:以非事务方式执行操作,如果当前存在事务,则抛出异常。PROPAGATION_NESTED
:如果当前存在事务,则在嵌套事务中执行。如果没有事务则按照REQUIRED执行。
示例
下面我们通过两个示例来演示这两个属性。
示例1:隔离级别的设置
/**
* 隔离级别的示例类
*/
@Service
@Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRES_NEW)
public class IsolationService {
@Autowired
private UserDao userDao;
/**
* 转账方法
*
* @param from 转出账户
* @param to 转入账户
* @param amount 转账金额
*/
public void transfer(String from, String to, double amount) {
// 查询转出账户并扣除余额
User fromUser = userDao.getUserByName(from);
fromUser.setAmount(fromUser.getAmount() - amount);
userDao.updateUser(fromUser);
// 查询转入账户并增加余额
User toUser = userDao.getUserByName(to);
toUser.setAmount(toUser.getAmount() + amount);
userDao.updateUser(toUser);
}
}
在上面的示例中,我们通过@Transactional
注解设置了事务的隔离级别为ISOLATION_REPEATABLE_READ
,传播特性为PROPAGATION_REQUIRES_NEW
。
该示例中的transfer
方法用于实现两个用户之间的转账操作,其中查询用户并修改余额的过程,需要保证在同一个事务中执行,而且在查询不同用户的余额时也需要保证数据的一致性,因此需要将事务的隔离级别设置为ISOLATION_REPEATABLE_READ
。
而且在转账过程中,如果出现异常需要回滚时,需要只回滚当前事务,而不回滚之前的事务,因此需要将传播特性设置为PROPAGATION_REQUIRES_NEW
。
示例2:传播特性的设置
/**
* 传播特性的示例类
*/
@Service
@Transactional
public class PropagationService {
@Autowired
private IsolationService isolationService;
@Autowired
private UserDao userDao;
public void withdraw(String userName, double amount) {
User user = userDao.getUserByName(userName);
user.setAmount(user.getAmount() - amount);
userDao.updateUser(user);
}
public void transfer(String from, String to, double amount) {
isolationService.transfer(from, to, amount);
}
public void pay(String from, String to, double amount) {
// 模拟支付过程
withdraw(from, amount);
// 模拟转账过程
transfer(from, to, amount);
}
}
在上面这个示例中,我们实现了一个支付流程,其中模拟了从一个用户账户中扣款和向另一个用户账户转账两个操作。这两个操作都是在事务内部进行的。而在最终的支付流程中,需要先完成扣款操作,然后再进行转账操作。也就是说,如果扣款操作失败,则转账操作不应该执行。
但是如果我们只在withdraw
方法上加@Transactional
注解,而不加在pay
方法上,则在withdraw
方法执行之后,即使发生异常,余额也已经被减少了,这是不可取的。因此,我们需要将pay
方法也加上@Transactional
注解,并设置其传播特性为PROPAGATION_REQUIRES_NEW
,这样才能做到各自独立的事务,出现异常时互不干扰。
总结
在Spring框架中,@Transactional
注解是非常常用的,特别是在服务层开发中。isolation
和propagation
两个属性可以用于控制事务的隔离级别和传播特性,帮助我们实现各种不同的事务场景。掌握这两个属性的使用方式,对于实现可靠的业务逻辑非常重要。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅谈spring中isolation和propagation的用法 - Python技术站