事务理解(个人理解,平常用了拿来看)

事务

mysql常用引擎:myisam和innodb;前者不支持事务,后者支持;

事务(Transaction):一组sql语句;

回退(Rollback):撤销未保存到数据库的sql语句操作;

提交(commit):未保存结果到数据库的sql语句进行保存操作;

保留点(savepoint):回滚事务的时候可以回滚到指定位置;

在这里插入图片描述

回滚只能用于INSERT,UPDATE,DELETE操作;SELECT使用回滚无意义;

回滚不能撤销CREATE和DROP(DDL)命令;


自动提交隐式提交

innodb的自动提交(Auto Commit)和隐式提交(Implict Commit);

自动提交:不开启事务的情况下,每一条sql语句执行完都会自动提交;

默认是会进行自动提交的;设置AUTOCOMMIT = 0之后不会自动提交;

这个属性是针对连接而非整个服务器;

如果会话1设置AUTOCOMMIT=0;会话2没有修改,查询AUTOCOMMIT的值就会是默认的1;

隐式提交:开启事务的情况下,如果这组sql中存在CREATE或DROP命令(DDL),则此命令之前的sql会被隐式提交,就算最后进行回滚,也只能回滚CREATE或DROP命令之后的sql;DDL语句和用来隐式修改mysql架构的操作,管理语句都会引起隐式提交;


事务分类

扁平事务:也就是最常用也最简单的事务,事务中的sql要么全部执行或全部失败,做不到一部分回滚一部分提交,因为扁平事务默认只有一个保存点且是在begin事务开始的位置;

带有保存点的事务:可以在事务中添加保存点,需要回滚的时候可以选择全部回滚还是某个保存点之后的sql回滚;

链事务:在提交一个事务时,释放不需要的数据对象,将必要的处理上下文隐式地传给下一个要开始的事务,提交事务操作和开始下一个事务操作 将合并为一个原子操作,这意味着下一个事务将看到上一个事务的结果,就好像一个事务中进行的一样;

嵌套事务:由一个顶层事务,控制各个层次的事务;像是一棵树,叶子节点是扁平事务,每个子事务从根到叶子节点的距离可能是不同的;

分布式事务:分布式环境下的扁平事务,多个数据源,保证ACID特性;


隔离级别

READ UNCOMMITTED

可以读取其他事务未提交的数据;会引起脏读;不加锁,裸奔;

READ COMMITTED

可以读取其他事务已提交的数据;会引起不可重复读;

一致性非锁定读(每次读取被锁定行最新的一份快照数据);

开启事务后,A事务查询列表,B事务插入一条数据并提交,这时A事务再去查询列表,同一个事务中两次相同的查询结果不同称为不可重复读

REPEATABLE READ

在同一事务中,每次读取的时候看到的都是相同的数据(相同的数据:不是指开启事务的那一刻,而是读取事务开始后第一次读取时行的快照数据);

在可重复读的隔离级别,分为快照读和当前读,一致性非锁定读都是快照读,一致性锁定读和写是当前读;快照可以读取当前事务的写,快照创建时间>其他事务提交时间可以读取到)

采用Next-Key lock算法减少幻读,不仅锁住扫描到的索引,还会锁住这些索引覆盖的范围;

一致性非锁定读中的快照是多版本并发控制(MVCC)来实现:

每行数据增加两个隐藏列实现,创建版本号和删除版本号;

查询:读取创建版本号<=当前事务版本号,删除版本号为空或>当前事务版本号;

创建:保存当前事务版本号为创建版本号;

删除:保存当前事务版本号为删除版本号;

修改:插入一条新数据,保存当前事务版本号为创建版本号,同时保存当前事务版本号为原来删除行的删除版本号;

会引起幻读:A事务进行查询用户名==‘X’,B事务添加了一条用户名='X’的数据并提交,当A事务用户名唯一校验通过准备添加时,发现唯一用户名冲突,因为不可重复读,A事务看不到B事务添加的数据,最后导致唯一用户名冲突,称为幻读;

SERIALIZABLE

串行化,可以避免幻读;隔离级别为序列化时为每个读操作加上共享锁;读占用了锁,对一致性的非锁定读不再予以支持(一致性的非锁定读就是快照读);

串行化隔离级别主要用于分布式事务;

分布式事务:允许多个独立的事务资源参与到一个全局的事务中;在分布式事务中innodb的隔离级别必须设置为SERIALIZABLE;


行锁,间隙锁,Next-Key锁

行锁:单个行记录上锁,总会锁住索引记录,如果没有任何一个索引,则会将隐式的主键进行加锁;

间隙锁:锁定索引记录间隙,确保索引记录的间隙不变。间隙锁是针对事务隔离级别为可重复读或以上级别的;

Next-Key锁:行锁+间隙锁;

在默认的隔离级别下,加锁查询使用Next-Key锁,加锁查询唯一的索引列会降级为行锁;

在这里插入图片描述


悲观锁乐观锁

悲观锁:为了保证事务的隔离性,需要一致性锁定读,读加共享锁,写加排它锁;

乐观锁:数据库表增加version字段来标识,每次修改版本递增,修改的时候对比之前查的版本,如果小于等于才进行修改,否则就放弃这次修改;


阻塞

一个事务中的锁需要等待另一个事务的锁释放它所占用的资源,称为阻塞;

在innodb中,阻塞等待默认是50秒,通过innodb_lock_wait_timeout来控制;

阻塞超时后可以进行回滚,使用innodb_rollback_on_timeout来设定超时是否进行回滚(默认是不进行回滚的);

阻塞超时导致的问题:

1,A事务查询id小于10的数据并加排他锁,因为隔离级别是可重复读,根据Next-key Lock算法,MySQL会将所有id小于等于10的数据都加排它锁;

2,B事务添加一条数据,id大于10,正常添加;

3,B事务添加一条数据,id小于10,因为A事务加了锁,最后导致B事务拿不到锁而报错,但是默认是不进行回滚的,也没有进行保存,但是id大于10的那一条数据在A事务的会话中依旧存在;


死锁

两个或两个以上事务执行过程中,因争夺锁资源而导致的一种互相等待的现象;

发生死锁后,MySQL会自动回滚某一个事务(一般是undo log记录小的事务);

通过锁的信息链表和事务等待链表可以构造出一张图,图中若存在回路,则代表存在死锁,因此资源间相互发生等待;


丢失更新

A事务开启,将x修改为y,这时B事务开启,将x修改为z,A事务提交,B事务提交,但是结果变成了z,A的更新丢失了;如果是关乎钱的问题就严重了,两个事务同时进行加钱操作,最后发现只加了一份钱;

​ 解决方案就是:开启事务后,加锁,其他的就要进行等待;


传播类型

Spring中七种传播类型:

外内外进行测试,内层设置不同的传播类型;

  • REQUIRED:如果不存在事务,创建一个,存在就加入;
    • 1,外抛异常回滚结果:全部回滚;
    • 2,内抛异常回滚结果:全部回滚;
    • 3,内抛异常try回滚结果:外正常执行,内:异常前正常保存,异常后没保存;(属于事务失效,不符合原子性)
  • SUPPORTS:如果不存在事务则以非事务运行,有就加入;
    • 外层存在事务的情况和第一种一样,不存在事务的情况就是报错程序奔溃,但是崩溃前插入的数据已存在数据库;
    • 内层trycatch后不影响外层数据插入,内层异常前正常保存,异常后没保存;(不符合原子性)
  • MANDATORY:不存在事务就报错,存在就加入;
    • 外层调用内层方法之前的数据正常保存,因为内层方法事务的传播类型为MANDATORY,程序报错崩溃结束;
  • REQUIRES_NEW:创建一个新事务,如果存在,则暂停当前事务;
    • 外层不会影响内层;内层报错外层也会回滚;
    • 内层中try catch的话,异常前正常保存,异常后没保存;(事务失效)
    • 内外层不使用同一个事务,使用的时候外层调用内层加trycatch,不是在内层中加trycatch,否则事务失效,这样内外层回滚互不影响;
  • NOT-SUPPORTS:以非事务方式执行,如果存在则暂停当前事务;
    • 外层报错不影响内层;内层报错影响外层,内层异常前正常保存,异常后没保存,外层回滚;
  • NEVER:以非事务方式运行,存在就报错;
    • 和平常不使用事务没区别,就多了一个存在事务报错;
  • NESTED:如果当前事务存在,则在嵌套事务中执行,否则行为类似于REQUIRED;
    • 外层如果不存在事务,则内层创建一个事务执行;
    • REQUIRED会跟着外层一同提交,一同失败 。
    • NESTED是内层出现异常,本身进行回滚操作,但是外层不会进行回滚操作,不过如果外层发生异常,内层会进行回滚操作 ;

常用的应该:

  • REQUIRED:一起回滚,一起提交;
  • REQUIRES_NEW:内外层不存在于一个事务中;
  • NOT-SUPPORTS:不管外层有没有事务,内层不使用事务;
  • NESTED:外层影响内层,内层不影响外层;

事务失效

在指定的传播类型下,发生不符合指定类型的情况;

1,把异常trycatch住了;

2,不存在事务,被调用的private方法上有@Transactional注解;

3,不存在事务,同一个类被调用的方法上有@Transactional注解;

 testTx方法不会产生事务
testTx方法不会产生事务;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值