mysql锁
性能:乐观锁,悲观锁
操作类型:读锁,写锁,都属于悲观锁
操作粒度:行锁,表锁
乐观锁:一种思想,通过版本控制,字段控制
悲观锁:读锁,写锁
行锁:每次锁住一条数据;开销大,加锁慢;可能出现死锁;发生锁冲突概率低,并发高。
innoDB支持行锁,其是针对索引加的行级锁,没有索引会升级为表锁。demo参考:https://www.cnblogs.com/bestzhang/p/10278592.html
innodb会分析使用索引和全表扫描的开销,选择是否使用索引,也会导致即使我们认为使用索引对应行锁,但实际也是表锁。具体分析见上文trace工具
表锁:每次锁住整张表;开销小,加锁快;不会出现死锁;发生锁冲突概率高,并发低。
myisam支持表锁,每次查询会加读锁,增删改会加写锁。
读锁:读锁阻塞任意session的写,不阻塞任意session的读;其他session可以再加读锁,不可以加写锁。
select * from table where xxx lock in share mode;
写锁:写锁阻塞其他session的任意读写操作,不阻塞当前session的读写操作;其他session不可以加任意锁。
select * from table where xxx for update;
间隙锁(Gap Locks)(重点)
间隙锁是封锁索引记录中的间隔,或者第一条索引记录之前的范围,又或者最后一条索引记录之后的范围。
临键锁
是记录锁与间隙锁的组合,它的封锁范围,既包含索引记录,又包含索引区间。
1.唯一索引只有锁住多条记录或者一条不存在的记录的时候,才会产生间隙锁,指定给某条存在的记录加锁的时候,只会加记录锁,不会产生间隙锁;
2.普通索引不管是锁住单条,还是多条记录,都会产生间隙锁;
3.间隙锁会封锁该条记录相邻两个键之间的空白区域,防止其它事务在这个区域内插入、修改、删除数据,这是为了防止出现 幻读 现象;
4.事务级别是RC(读已提交)级别的话,间隙锁将会失效。
死锁
事务(隔离级别,传播行为,mvcc,事务失效)https://www.jianshu.com/p/9a0b6e07df61
ACID
原子性:所有操作要么全部执行,要么都不执行
一致性:事务开始与结束,数据要保证一致状态
隔离性:独立执行,也就是中间状态外部不可见
持久性:数据操作结果的永久性
脏读:session1修改了数据,session2读到了该数据,session1又回滚了,session2读的就是脏数据
不可重复读:session2使用固定条件查询,session1修改了数据并提交,session2用同样的条件查询发现数据不一致
幻读:session2使用固定条件查询,session1新增了数据并提交,session2用同样的条件查询发现数据不一致
读未提交(READ UNCOMMITTED):可以读到其他事物未提交的数据。
读已提交(READ COMMITTED):可以读到其他事物修改+新增并提交的数据,避免脏读,会出现不可重复度和幻读。
可重复读(Repeatable Read):可以读到其他事物新增并提交的数据,避免脏读与不可重复读,会出现幻读,但是mysql底层通过mvcc将幻读做了很大优化。
串行化(SERIALIZABLE):两个事物顺序执行,避免脏读,不可重复读和幻读。通过两阶段锁实现,获取到sql(行/表)资源时加锁,整个事物结束才会释放锁。具体加读锁还是写锁不确定,估计是根据sql来的。
mvcc并发版本控制
只在RC和RR起作用,因为RU获取最新数据,串行化加锁,与并发版本控制概念冲突
innodb在数据库每行数据后边默认添加三个字段
1.事务id(DB_TRX_ID):标识最后一次修改(insert/update)本行记录的事务id,操作一次+1,删除在innodb内部视为更新,该记录标识位标记为已删除
2.回滚指针(DB_ROLL_PTR):指向写入undolog的数据记录
3.主键id(DB_ROW_ID):没有主键会生成,有则不生成
快照读:普通的查,属于快照读,不加锁
当前读:特殊的查,如select ... lock in share mode,select ... for update,insert,update,delete),属于当前读,需要加锁
mvcc快照读原理以及RR与RC实现区别--查询原理
只有其他事物修改了数据才会生成事物id,普通查询会生成一致性视图read view,readview由未提交的事务id数组(最小的min_id)和已创建(未提交+提交)的最大事务id(最大的max_id)组成,查询时跟readview作对比得到快照结果。--readview:[100,200],300
如果是RR,当前事务会在第一次查询时候生成的readview作为快照结果也就是事物300,后续其他事务如事物100事物200有修改数据并提交,当前事务再次查询时会使用第一次查询的readview得到的快照结果,所以RR可以避免不可重复度(两次查询结果数据一致),并且可以避免部分幻读(普通查询使用快照读没问题,但是特殊查询/修改等操作会使用当前读)。
注意:上边说的第一次查询是以事务session为级别,只要有一条查询,无论查的是哪张表,readview就生成了。
如果是RC,当前事务在第一次查询时候生成的readview作为快照结果,后续其他事务有修改数据并提交,当前事务再次查询时重新计算最新的readview生成快照结果,也就是会产生不可重复读(两次查询结果数据不一致)
RC:开启事务后,每次select都会重新创建ReadView
RR:开启事务后,每次select时,创建ReadView
mvcc增删改原理
修改:写锁锁定该行数据(最新版本,使用的是当前读获取数据),记录redolog,将当前的数据赋值到undo log,修改表中当前值行的值,修改事务编号,修改回滚指针指向undo log中修改前的行。
删除:删除可以认为是修改的特殊情况,也会将最新版本数据复制一份并修改回滚指针等,同时会在该条记录的头信息(record header)中的deleted_flag标志位改为true,表示该记录已经被删除。
redo/undo/binlog
刷盘机制:http://www.manongjc.com/detail/27-ooztzdqdivodtyx.html
https://blog.csdn.net/Merciful_Lion/article/details/124715392
重做日志redolog:事务开始就写入redolog,事务执行过程中,会直接写入,事务提交后,redolog就完成了使命释放掉。通过redolog保证事务的持久化。redolog是基于事务层面的;redolog是数据修改的物理记录。
回滚日志undolog:事务发生之前,当前数据的版本,可用于事务回滚,可用于mvcc快照读。事务提交后不会立即删除,有专门的线程会通过回滚指针等信息判断是否是老的undolog从而进行清理。
二进制日志binlog:用于主从同步,事务提交后将所有数据记录到binlog中,超过配置的天数后释放。binlog是基于数据库层面的;binlog可以认为是逻辑语句sql。
传播行为
解决@Transactional注解不回滚
是否为innodb引擎,异常类型是否支持,是否被catch住了
是否开启注解的解析,spring是否能扫描到对应的包
是不是public方法,是不是内部方法调用
解决内部方法调用:在当前处理service中注入本身service,自调用
网友评论