新人菜鸟一枚欢迎指摘
目录
事务,锁,MVCC
事务
事务A读取了事务B中尚未提交的数据。如果事务B回滚,则A读取使用了错误的数据
——脏读
不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间 隔,被另一个事务修改并提交了。
——不可重复读
在事务A多次读取构成中,事务B对数据进行了新增操作,导致事务A多次读取的数据不一致。
——幻读
对于第一类事务丢失,就是比如A和B同时在执行一个数据,然后B事务已经提交了,然后A事务回滚了,这样B事物 的操作就因A事物回滚而丢失了。
——回滚丢失
对于第二类事务丢失,也称为覆盖丢失,就是A和B一起执行一个数据,两个同时取到一个数据,然后B事务首先提 交,但是A事务加下来又提交,这样就覆盖了B事物.
——覆盖丢失
ACID
Atomicity原子性
Consistency一致性
Isoloation隔离性
Durability持久性
事务的隔离级别
select @@tx_isolation;
Read Uncommited 最差,未提交事务也能读到,不使用。
Read Commmited 可以读取最新结果记录
Repeatable Read 不可以读取最新结果记录
Serializable 最严格,按顺序执行,效率差,不适用。
预备知识
1.3个隐藏字段
DB_TRX_ID:创建或最后一次修改该记录的事务id
DB_ROW_ID:隐藏主键
DB_ROLL_PTR:回滚指针——事务回滚指向上一个历史记录
2.回滚日志 - undolog
保留的历史版本状态。
在执行一个对已有数据进行修改的时:
-
给事务添加排他锁,防止其他事务修改;
-
将数据保存到undolog;
-
修改的数据中的DB_TRX_ID+1,DB_ROLL_PTR指向undolog
-
当不同事务对同一条记录做修改时,会导致该记录的undolog形成一个线性表(链表),链表的链首是最新的历史记录,而链尾是最早的历史记录。
3.当前读与快照读
-
当前读
读取的是数据的最新版本,总是读取到最新数据
select...... lock in share mode读锁
select...... for update写锁
-
快照读、
读取的是历史版本数据
select
MVCC隔离算法
目的就是在并发且不加锁的状态下,提高数据库的读写效率,并且能保证数据一致性。
readView
——事务在快照读时产生的读视图
readView会产生
-
trx_list(系统活跃的id)
-
up_limit_id(列表中活跃事务最小的id)
-
low_limit_id(系统尚未分配的下一个事务id)
MVCC基石:3个隐藏字段,undolog日志,ReadView(读视图)。
if(DB_TRX_ID<up_limit_id) 则当前事务能看到DB_TRX_ID所在的记录; if(DB_TRX_ID>=low_limit_id) 则证明该事务是在ReadView产生之后才出现的,那么对于当前事务不可见; else{ if(trx_list.contains(DB_TRX_ID)){ 还未提交的事务,那肯定不可见; } else if(!trx_list.contains(DB_TRX_ID)){ 说明在ReadView生成之前就已经commit,那么修改结果是能看到的; } }
ReadView生成的时机是不同的
RC:每次进行快照读的时候都会生成新的ReadView
RR:只有第一次进行快照读的时候才会生成ReadView
然而在存在当前读和快照读的事务中MVCC是不起作用的,原因很简单:
当前读总是产生最新数据,快照读产生新的读视图。
例子:进行增删查是属于当前读,进行增删改时,不仅会增删改还会对另一个事务产生的结果进行修改,不难想象,此时的快照读也以这次当前读为依照了。
——产生了幻读问题
...锁的处理待更新