MySQL事务

MySQL锁:
共享锁(读锁):其他事务可以读,但不能写。
排他锁(写锁) :其他事务不能读取,也不能写。

MyISAM vs Innodb
1、MyISAM不支持事务。
2、MyISAM仅支持表级锁,不支持行锁。
3、MyISAM不支持外键。
4、MyISAM数据和索引分开存储。

事务四大特征(ACID):
原子性(A):事务是最小单位,不可再分。
一致性(C):事务要求所有的DML语句(data manipulation language,包括INSERT、UPDATE、DELETE)操作的时候,从一个一致性状态到另一个一致性状态。
隔离性(I):事务A和事务B之间具有隔离性
持久性(D):是事务的保证,事务终结的标志(内存的数据持久到硬盘文件中)

隔离性有4个隔离级别,从上往下隔离强度逐渐增强:
读未提交:read uncommitted。事物A未提交的数据,事物B可以读取到,这里读取的数据叫“脏数据”。
读已提交(Oracle默认隔离级别):read committed。事物A提交的数据,事物B才能读取到。
    虽然可以避免“脏数据”,但是会导致“不可重复读取”,也就是在事务B中,事务A进行了提交,导致在事务B的不同时刻读取到的数据不同。
可重复读(MySQL默认隔离级别):repeatable read。事务A提交之后的修改数据,事务B忽略,但是可以读取到插入数据,会导致“幻读”。
    可重复读针对的是更新问题,如UPDATE;幻读针对的是数据行的增删问题,如INSERT、DELETE。
    针对SELECT,采用事务开始时的快照读。针对SELECT ... FOR UPDATE、 UPDATE、INSERT、 DELETE采用当前读,加锁,以防其他事务提交时,写入冲突。
    可重复读是在事务开始的时候生成一个当前事务全局性的快照,而读提交则是每次执行语句的时候都重新生成一次快照。
    加锁的过程要分有索引和无索引两种情况,对于有索引的情况,MySQL直接就在索引中找到了这行数据,然后干净利落的加上行锁就可以了。
    对于无索引的情况,MySQL会为所有的行加行锁(非表锁),然后把不符合条件的行锁释放。
    但是MySQL把行锁和间隙锁(在事务A提交之前,事务B的插入操作只能等待)合并在一起,同时解决了并发写和幻读的问题,这个锁叫做 Next-Key锁。
    


    在有索引的情况下,只在取值的左右两边加间隙锁,没有索引就要整表加间隙锁了。

MySQL并未彻底解决幻读。
参考:MySQL 可重复读隔离级别,彻底解决幻读了吗? - 知乎 (zhihu.com)

串行化:serializable。事务A在操作数据库时,事务B只能排队等待,吞吐量太低,体验差,也很少用。
参考: 百度安全验证 

死锁的要素:
1、两个或者两个以上的事务。
2、每个事务都已经持有锁,并且申请新的锁。
3、锁资源只能被一个事务持有,或者不兼容。
4、事务之间因为持有锁和申请锁,导致彼此循环等待。
横向是已持有锁,纵向是正在请求的锁:

参考:https://www.jianshu.com/p/4d47261d3e6b
如何避免死锁?即解决方法。
1、尽量少加锁,减少锁的范围。
1)尽量使用索引、主键去操作,范围查找会使锁的范围加大,增加锁冲突的概率。同时区分度高的列放在组合索引的前面。
2)对于间隙锁,避免更新或者删除不存在的记录,虽然更新存在的记录也会产生间隙锁,但是间隙锁锁住的范围会更小;更新不存在的记录会锁住意想不到的区间范围,极其容易导致死锁问题。
2、控制锁持有的时间。
1)小事务
2)调整SQL的执行顺序,写的往后放。
3、尽量不要交叉持有锁。
以固定的顺序访问表、行。
参考:解决死锁之路 - 常见 SQL 语句的加锁分析 - 简书
MySQL查询where条件的顺序对查询效率的影响 - Acode - 博客园

MVCC机制:
主要是通过保存快照来实现。
通过MVCC实现行级锁,尽量避免加锁操作,提高并发能力。只在RC和RR隔离级别下生效。
当事务隔离级别设置为可重复读时,事务A执行select之后,如果事务B修改了数据,事务A再select依然是上一次的数据。
但是如果用insert、update和delete时,采用的数据就会是事务B修改后的数据。
比如事务A第一次查询到的age是23、事务B将age加1,事务A第二次查询age依然是23;如果事务A将age加1,再查询就是25。
最大的好处是,读不加锁,读写不冲突。
参考:MySQL 加锁处理分析(MVVC、快照读、当前读、GAP锁(间隙锁))_destinm的博客-CSDN博客_当前读 间隙锁

Spring框架的事务基础架构代码将默认地只在抛出运行时和unchecked exceptions时才标识事务回滚。
1 让checked例外也回滚:在整个方法前加上 @Transactional(rollbackFor=Exception.class)
2 让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)
3 不需要事务管理的(只查询的)方法:@Transactional(propagation=Propagation.NOT_SUPPORTED)
4 如果异常被try{}catch{}了,事务就不回滚了,如果想让事务回滚必须再往外抛try{}catch{throw Exception}。

事务的传播行为:如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。

@Transactional注解使用禁忌:
1、不建议将Transactional标注在Interface上
2、不能将Transactional标注在private、protected方法上
3、不能将Transactional标注在被内部调用的方法上
这是由Spring AOP(Aspect Oriented Programming,面向切面编程)决定的,所以同样适用于Spring的其它注解。参考:https://www.jb51.net/article/137255.htm

常用日志文件
redo log:重做日志,持久性。物理逻辑存储,存储每页的逻辑修改,循环存储。
undo log:回退日志,原子性。事务回退,MVCC(多版本并发控制下的读)。
binlog:二进制日志,隔离性。用于主从复制(同步复制、半同步复制、异步复制)或者是像canel那样模拟一个假的slave监听数据库表的修改用于缓存数据同步。
binlog是MySQL本身的,redo log和undo log是Innodb存储引擎的。
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值