事务那点事

发布日期:2019-03-22

一、事务的基本要素(ACID)

  1、原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体

   2、一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。

   3、隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此互不干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。

   4、持久性(Durability):事务完成后,对数据的改变是永久性的事务对数据库的所有更新将被保存到数据库,不能回滚。

二、事务的并发问题

  ① 脏读:事务A对数据进行了更改,但未提交,事务B可以读取到未提交的数据。如果事务A这时候回滚了,那么事务B就读到了脏数据。

  疑问1:脏读,为啥别人能看到我未提交的数据?  答:因为其实你对数据库的任何修改都是立即生效的,至于别人看不看的到就是你加了锁没有加锁的事情了。数据库的执行和事务没有关系,事务只是控制这些对数据库所做的操作会不会撤销而已。       比如A读到了B正在修改的事务是因为B没有加锁,所以别人看到了,MySQL默认是行级锁,所以别人在改数据的时候是加了写锁的,所以别人都读不到这行数据,所以没有脏读问题。      ② 可重复读:事务A发生了多次读操作,多次操作之间,事务B对数据进行了修改并且提交,这时候读取的数据是不一致的。注:如果中间那个修改的事务没有提交,则读事务看不到修改结果. 在默认的隔离级别下         

     ③ 幻读:事务A对表进行批量修改,事务B在表里新增数据或者删除,这时候事务A就会丢失对新增数据的修改。发现了自己修改以外的数据就像是发生了幻觉一样 .     出现幻读原因 : 因为MySQL的Innodb引擎是默认使用行级锁,没使用表级锁,当我对表中多行数据进行修改的时候,其实也只是锁住了选中的那些行,其他线程插入了新数据是当然可以的 也就是事务A根本不知道事务B插入的数据     如果使用了MySQL 表级锁的的引擎比如MyIsAM,幻读自然就没可能出现了。       --------------------- 不可重复读侧重于修改,幻读侧重于新增删除

三、MySQL事务的隔离级别 (对应基本要素中的隔离性)

  是:代表会出现脏读不可重复读幻读情况

事务隔离级别脏读不可重复读幻读
读未提交(read-uncommitted)
不可重复读(read-committed)
可重复读(repeatable-read)
串行化(serializable)

 MySQL默认的隔离级别是可重复读(repeatable-read)

    Spring对事务的默认隔离级别是使用的数据库的隔离级别.    orcale, sqlserver的行级锁只有排他锁没有共享锁,默认不是使用锁机制。而是通过版本控制,不会脏读,但是他会出现重复读问题,因为没锁住这行数据,别人当然可以读。

三、Spring中事务的传播行为 

事务传播行为类型说明
PROPAGATION_REQUIRED如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
PROPAGATION_SUPPORTS支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

 Spring默认使用的是PROPAGATION_REQUIRED

 

    转载请注明原创.谢谢.