Spring的事务管理机制
Spring的事务管理机制
事务是一组操作的集合,是一个不可分割的操作。事务会将所有的操作视为一个整体向系统提交或撤销操作请求,这一组操作集合要么全部成功,妖媚全部失败。
Spring声明式事务@Transactional
Spring中也为事务提供了支持,通过@Transactional
注解在方法执行前自动开启事务,方法执行完毕之后自动提交事务。如果这个方法在执行过程中出现异常就会自动进行事务的回滚。
@Transactional
- 可以用来修饰方法或类。@Transactional注解默认只对public方法生效,这是由于Spring的事务管理是基于动态代理1现的
为了更好的观察Spring事务管理相关信息,我们可以在application.yml
配置文件中开启事务管理日志,观察其日志信息。
#spring 事务管理日志
logging:level:org.springframework.jdbc.support.JdbcTransactionManager: debug
访问对应接口,如下:
@Service
@Slf4j
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;@Transactional //开启Spring的事务管理@Overridepublic void save(User user) {log.info("[UserService#save]: 开始执行");userMapper.insert(user);log.info("[UserService#save]: 结束执行");}
}
观察控制台输出日志,如下:
- 程序正常运行结束
观察数据库,数据正确插入:
- 程序异常结束
观察数据库,数据回滚没有保存到数据库中:
@Transactional常见的三个属性
-
rollbackFor
:异常回滚属性,指定能够出发事务回滚的异常类型。 -
isolation
:控制事务的隔离级别,默认隔离级别为Isolation.DEFAULT
。 -
propagation
:事务的传播机制,默认传播行为为Propagation.REQUIRED
。
rollbackFor
我们知道通过@Transactional注解进行事务管理时,当该方法发生异常时会执行rollback回滚操作,那么是不是什么类型的异常都会执行rollback操作呢?
如果不进行显示指定,默认情况下只有出现RuntimeException及其子类和Error及其子类才会回滚事务。
//如果还需要指定对特定异常的回滚,可以通过rollbackFor属性进行指定
@Transactional(rollbackFor = [...])
isolation
SQL标准定义了四种隔离级别:
隔离级别 | 解释 |
---|---|
READ UNCOMMITTED | 读未提交,该隔离级别可以看到其他事务中未提交的数据(脏读问题) |
READ COMMITTED | 读已提交,该隔离级别可以看到其他事务中已提交的数据(由于事务的执行中可能有多个事务提交,所以可能出现不可重复读问题) |
REPEATABLE READ | 可重复读,该隔离级别可能出现幻读问题 |
SERIALIZABLE | 串行化 |
在Spring事务中提供了五种隔离级别来支持sql标准的隔离级别:
spring提供的事务隔离级别 | 解释 |
---|---|
Isolation.DEFAULT | 以连接的数据库的事务隔离级别为主 |
Isolation.READ_UNCOMMITTED | 读未提交 |
Isolation.READ_COMMITTED | 读已提交 |
Isolation.REPEATABLE_READ | 可重复读 |
Isolation.SERIALIZABLE | 串行化 |
我们可以通过isolation属性进行设置
@Transactional(isolation = ...)
propagation
通过这个属性我们可以配置事务的传播行为,即当一个事务方法被另一个调用时,这个事务方法如何进行事务控制。
常见的事务传播行为:
属性值 | 含义 |
---|---|
Propagation.REQUIRED | 默认的事务传播级别,需要事务,有则加入,无则创建新事务 |
Propagation.REQUIRES_NEW | 需要新事务,无论有无,总是创建新事务 |
Propagation.SUPPORTS | 支持事务,有则加入,无则在无事务状态中运行 |
Propagation.NOT_SUPPORTED | 不支持事务,在无事务状态下运行,如果当前存在已有事务,则挂起当前事务 |
Propagation.MANDATORY | 必须有事务,否则抛异常 |
Propagation.NEVER | 必须没事务,否则抛异常 |
Propagation.NESTED | 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行。如果当前无事务,则创建新事物 |
动态代理是通过创建代理对象来拦截对目标对象的方法调用。代理对象只能调用目标对象的公共方法(因为代理对象通常是一个新生成的类,它要么实现了和目标对象相同的接口(JDK动态代理),要么是目标对象的子类(CGLIB代理))。对于非公共方法,代理对象无法直接调用,因为它们在外部不可见。 ↩︎