在Spring的官方文档的Features里面Spring的事务作为数据访问的特性被特殊的列了出来,那么Spring的事务和我们平常使用MySQL时手动开启的事务有什么区别呢,其实本质上是没有区别的,只是我们手动的开启事务,提交事务/回滚事务的操作由Spring替我们完成了,仅仅这些还是不够的,Spring在这些基础的操作上也针对数据库的事务做了一些增强。
Spring在官方文档里定义了接口规范给不同的数据源厂商去提供标准,各个厂商去实现然后注入到Spring容器中就就好了,Spring定义的规范也特别的简单,获取当前事务,提交与回滚。 打开我们的编辑器来看看更多的关系。
因为我的依赖中使用的是Spring-jdbc,所以最底层的事务实现类就是org.springframework.jdbc.datasource.DataSourceTransactionManager 了,合理,非常的合理。 既然实现类都被我们找到了,那直接来一波Spring的编程式事务吧。
很easy的,无非就是开启事务,没错就提交,有错就回滚呀。
@Service
public class TransactionService {
private final PlatformTransactionManager transactionManager;
private final JdbcTemplate jdbcTemplate;
public TransactionService(PlatformTransactionManager transactionManager,JdbcTemplate jdbcTemplate) {
this.transactionManager = transactionManager;
this.jdbcTemplate = jdbcTemplate;
}
public void txBoot(){
TransactionStatus transaction =
transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
jdbcTemplate.update("UPDATE info_user SET sex = ? WHERE user_name = ?","女","lisi");
System.out.println("一段薛定谔的逻辑");
transactionManager.commit(transaction);
} catch (DataAccessException e) {
transactionManager.rollback(transaction);
}
}
}
java
DefaultTransactionDefinition开启事务的时候传过去了一个这个东西,这是个啥呢,还记得数据库中的事务的隔离级别吗,这个东西就是用来定义当前事务的隔离级别的,并且还可以定义一些在Spring事务中的传播性,事务超时时间以及是否只读等等,因为这种编程式事务与业务代码的耦合度太高了,也很丑陋,所以编程式事务在我们日常开发中是用不到滴,上面的那些东西我在声明式事务中进行介绍。
因为Spring的优秀,声明式事务用起来就更简单了,Spring使用AOP的方式将事务的处理织入到了我们的业务代码中,如果你的项目里面用到了SpringBoot,你只需要在业务方法或是累上加上一个@Transactional注解就ok啦
那么问题来了,就这么一个简单的注解,我想要修改当前事务的隔离级别怎么办,别慌,这个注解里面还有很多属性,我们一眼就可以看明白。
常用的属性就上面那些,当然还有一些其他的你点开这个事务注解把源码下载下来,人家的注释很清楚的。
上面注解的意思就是,将当前连接的隔离级别设置为SERIALIZABLE�级别,这个隔离级别可以防止出现脏读,不可重复读和幻读,并且设置回归的异常类型为Exception,这个很重要哦,因为rollbackFor的默认值为RuntimeException运行时异常。
数据库的几个隔离级别很简单我就不在这里展开说了,上面说到了事务的传播性Propagation propagation() default Propagation.REQUIRED;
传播,顾名思义就是两个事务相遇了第一个事务对第二个事务有什么影响。
就像是上面那样。两个事务注解不一样该听谁的呢?莫慌这就是Spring的传播性要解决的问题了。
可以看到,@Transactional注解里面有一个事务传播的属性并且默认的事务传播类型为Propagation.REQUIRED,这个类型是什么意思呢,那还有没有其他的类型,我们来一一解释。
可以看到事务的传播类型不是很多哈。
但是我们在写代码时难免要捕获一些异常做一些特殊的处理,难道就只能自己处理数据的回滚了吗,当然不是,方法有很多,你一个把异常捕获了,在catch块中在抛一个异常给Spring,当然这种做法并不优雅,何为优雅,看我的。
那就是拿到当前的事务设置回滚。
用用户注册举个例子,用户注册成功之后要向MQ中发送一条用户注册成功的消息,优惠券服务,会员服务,消息通知服务就可以拿到消息做用户注册成功之后的业务逻辑处理了。发送MQ消息写到左后一行?把用户注册的业务逻辑代码try-catch了然后在finally里面获取当前事务的状态然后再决定是否发送,不优雅不优雅,统统不优雅。 因为Spring提供了一个叫做TransactionSynchronization接口
我们可以使用TransactionSynchronization接口处理类似于发送MQ消息这种逻辑。
代码太长了不够优雅?
优不优雅。