Spring Boot 事务详解

1.什么是事务

在数据库中,多条SQL执行语句(主要包含insert、update、delete)共同执行。其中某条发生了错误,前面执行过的SQL语句会回滚,后面的SQL执行语句不会执行,还原到执行前的数据。这样的一个执行过程被称为事务。

事务主要是为了确保数据的完整性,一切正常就全部执行,中间发生了错误就全部不执行。

MySQL中只有InnerDB数据引擎支持事务。

2.事务四大特性

事务具有ACID四大特性

  • A(Atomicity):原子性。事务中的工作单元划分到原子级别(各个SQL语句)。要么全部执行,要么全部不执行,不会在中间某个单元结束执行。例:扫码支付后,要么支付成功,要么支付失败。不会出现本人支付成功、商家没有收到钱情况。
  • C(Consistency):一致性。事务开始前和事务开始后,数据关联是一致的,数据完整性没有被破话。例:扫码支付100元,本人账户必定扣除100元,商家账户必定新增100元。
  • I(Isolation):隔离性。多个事务并发执行时,避免交叉执行导致数据不一致。例:多人同时扫码支付,减少的都是自己的钱,不会影响到其他人的账户余额。
  • D(Durability):持久性。事务执行完毕后,对数据的修改是长久性的。不会被修改、回滚回去。例:扫码支付成功后,你的账户减少的钱是一直都会生效的。

3.事务的隔离级别

多个事务同时并发操作同一数据时,数据可能会发生问题。为了解决事务并发导致的数据不一致性的问题,数据库提供了隔离级供我们使用。

并发产生的问题

  • 脏读:一个事务读到了另一个未提交事务修改过的数据
  • 幻读:一个事务先根据某些条件查询出一些记录,之后另一个事务又向表中插入了符合这些条件的记录,原先的事务再次按照该条件查询时,能把另一个事务插入的记录也读出来。
  • 不可重复读:一个事务只能读到另一个已经提交的事务修改过的数据,并且其他事务每次对该数据进行一次修改并提交后,该事务都能查询得到最新值。

隔离级别

  • 读未提交(Read Uncommitted):并发下,A事务可以读取到B事务未提交过的数据。容易发生脏读、幻读、不可重复读的线像。一版情况下数据库不会使用该隔离级别。
  • 读已提交(Read Committed):并发下,A事务比B事务开始执行,B事务如果要读取自己修改的数据,只能在A事务完成修改后已提交后,才能读取到。解决了脏读的问题,但可能发生幻读和不可重复读现像。
  • 可重复读(Repeatable Read):并发下,B事务若想读到自己修改的数据,只能在A事务修改过数据并提交后,自己也提交事务后,才能读取到。及解决了脏堵、幻读的问题,单可能发生不可重复读。
  • 可串行化(Serializable):并发下,最为严格的事务级别,所有事务按照次序依次执行,因此,脏读、不可重复读、幻读都不会出现。但是执行效率低下,一般不采用。

隔离级别级别越高对于数据库的性能影响越大:可串行化>可重复读>读已提交>读未提交

MySQL和Spring中默认的事务隔离级别是“读已提交”。

脏读幻读可重复读
读未提交
读已提交
可重复读
可串行化

4. SpringBoot中事务的配置

SpringBoot中如果使用事务直接在启动类上加上@EnableTransactionManagement即可。
然后在对应的service实现方法上加上@Transactional即可。

查看@Transactional源码

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
	// 事务执行默认值
    @AliasFor("transactionManager")
    String value() default "";
    
	// 事务执行默认值
    @AliasFor("value")
    String transactionManager() default "";

	// 事务的传播级别
    Propagation propagation() default Propagation.REQUIRED;

	// 事务的隔离级别,默认的是读已提交
    Isolation isolation() default Isolation.DEFAULT;

	// 事务超时时长,-1代表永不超时
    int timeout() default -1;
	
	// 是否设置为只读的事务
    boolean readOnly() default false;

	// 设置需要进行回滚的异常类数组
    Class<? extends Throwable>[] rollbackFor() default {};

	// 设置需要进行回滚的异常类名称数组
    String[] rollbackForClassName() default {};

	// 用于设置不需要进行回滚的异常类数组
    Class<? extends Throwable>[] noRollbackFor() default {};

	// 用于设置不需要进行回滚的异常类名称数组
    String[] noRollbackForClassName() default {};
}

这些配置中着重讲一下事务的传播机制和事务的隔离级别,隔离级别由于上文已经说了。这里只讲隔离级别。

事务的传播主要指的是A事务执行中用到了B事务,或者A事务和B事务同时在C事务中等这种事务嵌套的使用。

事务的传播行为主要分为七种。

  • PROPAGATION_REQUIRED: 如果执行时,已经在一个事务中,就加入该事务。否则就开启一个新的事务。是默认的事务传播行为

  • PROPAGATION_SUPPORTS:如果执行时,已经在一个事务中,就加入该事务。没有的话,就不以事务的方式进行。但是对于事务同步的事务管理器,PROPAGATION_SUPPORTS与不使用事务有少许不同。

  • PROPAGATION_MANDATORY:如果执行中,已经在一个事务中,就不能发起自己的事务。如果没有在一个事务中,就抛出异常。

  • PROPAGATION_REQUIRES_NEW:如果执行中,已经在一个事务中,则这个事务将被挂起。并开启一个事务执行当前业务方法。执行完毕后,回复原来挂起的事务继续进行。

  • PROPAGATION_NOT_SUPPORTED :总是非事务地执行,并挂起任何存在的事务。

  • PROPAGATION_NEVER :总是非事务地执行,如果存在一个活动事务,则抛出异常。

  • PROPAGATION_NESTED :如果业务方法在一个既有的事务中执行,则该业务方法将在一个嵌套的事务中进行;否则,按照TransactionDefinition.PROPAGATION_REQUIRED来对待。它使用一个单独的事务,这个事务可以有多个rollback点,内部事务的rollback对外部事务没有影响,但外部事务的rollback会导致内部事务的rollback。这个行为只对DataSourceTransactionManager有效。

5.事务什么情况下会失效

  • 1.数据库引擎是否支持事务(MySql的MyIsam引擎不支持事物)
  • 2.注解所在的类是否被加载成Bean
  • 3.注解所在方法是否为public修饰的
  • 4.是否发生了自调用问题
  • 5.所用数据源是否加载了事务管理器
  • 6.@Transactional的扩展配置propagation是否正确
  • 7.异常类型错误、异常被try cath 没有throw
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值