发布时间:2023-07-11 16:00
有这样的一个经典问题,用户A转账给用户B,是怎样保证数据的一致性的?这时就需要用到事务了。
事务是数据库管理系统执行insert、update、delete
过程中的一个逻辑单位,由一个有限的数据库操作序列构成
show variables like \'%autocommit%\'
begin 、commit/rollback
事务持有的锁在事务结束时释放1.脏读(可能会回滚)
2.不可重复读(update/delete)
3.幻读(insert)
查看数据库隔离级别sql show variables like \'tx_isolation\'
如何在一个事务里面保证两次查询一致?
1.在读数据前对其加锁,阻止其他事务对该数据加锁(LBCC,基于锁并发),高并发情况下,很不友好
2.生成一个请求时间点的一致性快照数据,用这个快照来提供一致性读(MVCC)
建立一个快照,同一个事务无论查询多少次,都是相同的数据
一个事务能看到的数据版本:
一个事务不能看到的版本
接下来从一张图来分析MVCC是怎么工作的:
MVCC是怎么实现的呢?为什么每次查询都能查到第一次查询的内容?
依赖的是Read View一致性视图
事务开启之后的第一次查询会建立这样的一个视图
1.从数据的最早版本判断(undo log)
2.数据版本的trx_id = creator_trx_id,本事务修改,可见
3.数据版本的trx_id < min_trx_id,当前事务版本在生成ReadView已经提交,可见
4.数据版本的trx_id > max_trx_id,当前事务版本是生成ReadView新开的事务的,不可见
5.数据版本的trx_id在min和max之间,看看是否还在mid[]列表中,在的话说明是未提交的,不可见,反之可见。
6.如果当前版本不可见,就找undo log链中的下一个版本。
在mysql中锁有表锁和行锁。
lock tables xxx read;
lock tables xxx write;
unlock tables;
-- 先加行锁
begin;
select * from student where id=1 FOR UPDATE;
-- 另一个窗口加表锁 不会成功
begin;
LOCK TABLES student WRITE;
begin;
select * from student where id=1 LOCK IN SHARE MODE;
commit/rollback;
delete/update/insert
默认加上排它锁show variables like \'innodb_lock_wait_timeout\'
, 默认50s-- 锁住 4
begin;
select * from student where id=1 FOR UPDATE;
commit/rollback;
-- 锁住区间 (4,7)
select * from t1 where id>4 and id<7 for update;
-- 假如一个表的索引记录只到10 锁住 (10,+无穷大)
select * from t1 where id>15 for update;
-- 索引记录是 1,4,7,10 会锁住(4,7],(7,10] 那么插入这个范围内的数据是会阻塞 读加锁用这种解决幻读
select * from t1 where id>4 and id<9 for update;
锁的作用:为解决资源竞争而存在
//需要先开启 --transaction 里面有记录死锁信息
show engine innodb status;
以上就是本章的全部内容了。
上一篇:mysql第五话 - mysql索引原理分析
下一篇:mysql第七话 - mysql性能优化总结
一日难再晨,岁月不饶人