事务基本信息

事务的特性

原子性: 事务一旦开始,后面所有的操作要么全部成功要么全部不成功,不允许停留在中间态,中间态对外不可见

一致性: 事务开始和结束后,数据的完整性没有被破坏;比如: A转账给B,不能出现A的钱被扣了,但B没收到钱。

            博客上看到了这么一句话感觉很合理: 一致性是事务的最终目的,原子性、隔离性、持久性都是为了实现一致性。

持久性: 事务的所有操作都必须持久化,哪怕出现宕机、停电等极端情况,重启后也不能丢失数据。

隔离性: 多个事务之间互不干扰,A事务先执行就不能读取到B事务的任何操作。

事务的隔离级别

事务要保证完全的隔离性,就必须对所有的操作按照表锁进行互斥,这样数据的安全性(正确性)是满足了,但是并发性能过低,于是出现了事务隔离级别。这样一来虽然提高了性能,但损失了一致性,这样一来就需要根据各自业务要求合理的选择适合的隔离级别;

Mysql默认可重复读级别解决了不可重复读问题,部分解决了幻读的问题(当前读获取数据会产生幻读,快照读不会)。

下面针对各个事务隔离级别进行说明

  • 读未提交

可以读取另一个事务还没提交的数据

  • 读已提交

只能读取事务已提交的数据

  • 可重复读(Mysql默认)

同一个事务内,多次读取的数据是一致的

  • 串行化

所有的读写操作按顺序执行,效率很差

从上往下,隔离强度逐渐增强,性能逐渐变差。采用哪种隔离级别要根据系统需求权衡决定,其中,可重复读是 MySQL 的默认级别。

事务隔离其实就是为了解决上面提到的脏读、不可重复读、幻读这几个问题,下面展示了 4 种隔离级别对这三个问题的解决程度。

不同隔离级别产生的问题

脏读: 两个事务A和B,A读取到了B修改但未提交的数据,此时如果B回滚了,那么A拿到的数据就是临时且无效的脏数据

幻读: 两个事务A和B,A读取了一个字段,然后B插入了一些新行,A再去读取的时候发现结果多了几行

不可重复读: 两个事务A和B,A读取了一个字段,然后B修改了这个字段,之后A再去读这个字段,发现字段值不一致

幻读和不可重复读区别

从总得结果上看,两者很相似,都表现为两次读取的数据不一致;从如何避免问题的角度上看还是有很大区别的;

  • 不可重复读只需要加上行锁就可以避免,幻读需要加上表锁才可以避免;
  • 不可重复读重点在于update,幻读的重点在于insert和delete,行锁可以控制不能操作update和delete,但是挡不住insert操作;
  • 两者最大的区别在于如何通过锁机制解决问题;

隔离级别不同对这三个问题的解决程度

隔离级别

脏读

幻读

不可重复读

读未提交

未解决

未解决

未解决

读已提交

解决

未解决

未解决

可重复读

解决

未解决

解决

串行化

解决

解决

解决

只有串行化解决了所有的问题,其他三个隔离级别都有缺陷

Spring 包装的事务

Spring 事务实现的方式有哪些?

编程式事务: 通过编程的方式管理事务,给你带来极大的灵活性,但是难维护。

声明式事务: 建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

Spring事务的实现方式和实现原理

Spring事务的本质其实就是对数据库事务的支持,没有数据库的事务支持,Spring无法提供事务功能。真正数据库层面的事务提交和回滚是通过binlog或者redo log实现的

Spring事务的传播行为

  • REQUIRED(默认)

业务方法需要在一个事务中运行,如果方法运行时,已处在一个事务中,那么就加入该事务,否则自己创建一个新的事务。这是spring默认的传播行为。

  • NOT_SUPPORTED

声明方法不需要事务。如果方法没有关联到一个事务,容器不会为他开启事务,如果方法在一个事务中被调用,该事务会被挂起,调用结束后,原先的事务会恢复执行。

  • REQUIRESNEW

不管是否存在事务,该方法总会为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务挂起,新的事务被创建。

  • MANDATORY

该方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果在没有事务的环境下被调用,容器抛出异常。

  • SUPPORTS

该方法在某个事务范围内被调用,则方法成为该事务的一部分。如果方法在该事务范围外被调用,该方法就在没有事务的环境下执行。(有事务就加入,没有也无所谓)

  • NEVER

该方法绝对不能在事务范围内执行。如果在就抛异常。只有该方法没有关联到任何事务,才正常执行。

  • NESTED

如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效。

假设A使用默认隔离级别,B使用NESTED那么此时如果B抛异常,A正常则B先回滚,A再正常提交;如果A抛异常则A和B一起回滚

Spring事务管理有哪些优点

  • 为不同的事务API 如 JTA,JDBC,Hibernate,JPA 和JDO,提供一个不变的编程模式。
  • 为编程式事务管理提供了一套简单的API而不是一些复杂的事务API
  • 支持声明式事务管理。
  • 和Spring各种数据访问抽象层很好得集成。

分布式事务

分布式事务顾名思义就是要在分布式系统中实现事务,它其实是由多个本地事务组合而成。

对于分布式事务而言几乎满足不了 ACID,其实对于单机事务而言大部分情况下也没有满足 ACID,不然怎么会有四种隔离级别呢?所以更别说分布在不同数据库或者不同应用上的分布式事务了。

  • 2PC(两阶段提交)

引入事务协调者,参与者概念,把事务分为准备阶段和提交阶段,但是一种同步阻塞的模型;协调者有超时机制但参与者没有

  • 3PC(三阶段提交)

2PC的变种,事务分为准备阶段,预提交阶段,提交阶段。参与者也引入了超时机制

  • TCC(Try - Confirm - Cancel)

业务层面的事务,不再局限于数据库操作。Try是预留资源,Confirm是确认执行,Cancel是撤销,对业务侵入较大和业务强耦合还需要保证操作的幂等性