关于MySQL的事务和使用注意等

  MySQL Oracle
默认事务级别 可重复读(Repeatable read) 已提交度(Read committed)
读数据一致性 事务级  语句级
事务级别问题 幻读,由于GAP锁的存在,可以解决幻读的情况。 不可重复读,幻读
事务加解锁情况 事务处理阶段只加锁,commit时才进行解锁  
MVCC
(读可不加锁,读写不冲突,乐观锁)
repeatable read级别下,总是读取当前 事务开始时的 快照数据。 read committed级别下,对快照数据总是读取 最新一份的 快照数据;
加锁情况 快照读:简单的select操作,属于快照读,不加锁。(当然,也有例外,下面会分析)

select * from table where ?;
====================================================
当前读:特殊的读操作,插入/更新/删除操作,属于当前读,需要加锁。

select * from table where ? lock in share mode;

select * from table where ? for update;

insert into table values (…);

update table set ? where ?;

delete from table where ?;

所有以上的语句,都属于当前读,读取记录的最新版本。并且,读取之后,还需要保证其他并发事务不能修改当前记录,对读取记录加锁。其中,除了第一条语句,对读取记录加S锁 (共享锁)外,其他的操作,都加的是X锁 (排它锁)。
 
锁升级 在InnoDB中有两种情况下会发生这种升级的情况:

单独的SQL语句在一个对象上持有的锁数量超过阈值,默认为5000条。
【需要是统一个对象的,不同对象不叠加】
锁资源占用的内存超过了激活内存的40%的情况。
 
阻塞情况 在事务中的锁冲突,需要等待其他线程释放资源的情况。默认情况下等待时间50秒,并且超时不会滚的。
所以大事务情况,很危险。
 
各种情况 情况1:update和delete语句的条件where必须使用索引,并且尽可能使用主键索引。
否则,全表扫描会出现大量锁数据的情况。
(即使高版本对此做了优化,在条件过滤之后,会解锁,但加解锁的开销依旧很大)
 
情况2:尽量不使用select...for update 语句。
会导致,数据被加上X锁,使的事务提交前,所有当前读操作等待。
通常也就是,其他事务的更新。
 
情况3:不创建相同字段的索引。(通常不创建唯一索引,可在业务层处理)
X锁定数据的同时,也会在对应索引上加X锁。
RR事务级别,在索引上还会加上GAP锁。
(例如:创建user_id的普通和唯一索引。
小杭个人分析认为,此情况下,通过普通索引update对数据加X锁时,会同时在唯一索引上也加上X锁。如此时,唯一索引被其他update使用,则会死锁,加锁是顺序的。)
具体解释看索引更新情况,更新的时候是会锁住的。
 
索引更新 对于数据的每一次更新,MySQL并不会每次都会更新索引(针对非唯一性索引而言)
在InnoDB中,增删改都会立刻修改主键or唯一索引,但是不会rebuild全局索引,对于非唯一性索引,InnoDB会进行change buffering操作。

参考:https://dev.mysql.com/doc/refman/8.0/en/innodb-change-buffer.html
 
参考文章: https://blog.csdn.net/xiaohangblog/article/details/96349540  
https://www.jianshu.com/p/13f5777966dd  
posted @ 2022-05-21 23:29  小-杭  阅读(38)  评论(0)    收藏  举报