数据库锁(三)
1.事务隔离级别概念
MySql中有四种隔离级别:
- 读未提交(Read Uncommited):允许一个事务可以看到另一个事务未提交的数据,会产生脏读,不可重复读,幻读;
- 读已提交(Read Commited):保证一个事务修改的数据提交后才能被另一个事务读取,避免脏读,会产生不可重复读,幻读;
- 可重复读(Repeatable Read,默认):保证一个事务不能读取另一个事务未提交的事务外,还可以保证避免不可重复读;
- 串行化(Serializable):事务顺序执行,代价高,最可靠。
存在的三个问题:
- 脏读:事务1更新了记录,但没用提交,事务2读取该记录,然后事务1回滚,事务2读取无效;
- 不可重复读:事务1读取一条记录,事务2更新该记录并提交,事务1再次读取,读取到了更新后的值,和第一次读取的值不同;
- 幻读:事务1读取记录,事务2增加记录并提交,事务1再次读取时看到了事务2新增的记录。
2.MVCC
多版本并发控制技术,是一种乐观锁的实现,通过保存数据在某个时间点的快照来实现。
2.1 Innodb的行结构
Innodb存储的最基本row中额外包含三个字段,DATA_TRX_ID,DATA_ROLL_PTR,DB_ROW_ID。
-
DATA_TRX_ID:6个字节,标记了最近修改(insert update)这条行记录的事务id,即最后一次修改记录的事务id; delete操作,在Innodb中也看作是一次update操作,用1个bit表示;
show engine innodb status
命令查看; -
DATA_ROLL_PTR:7个字节,是一个指针,指向这条记录的rollback segment(回滚段)的undo log记录;
update操作的话,记录update前的row值;
-
DB_ROW_ID:6个字节,新行插入而递增,如果表没用设置主键,生成聚簇索引时,适用该值,如果有主键,该值不会出现;
- DELETE BIT:标识该记录是否被删除,只是标记出来,真正的删除在commit的时候。
2.2 Read-View的结构
每个事务首次执行快照读操作时,会创建一个read_view对象(RR隔离级别中首次执行快照读创建对象,而RC隔离级别中每次执行快照读,都会创建对象),该对象就是用来控制逻辑快照的可见范围的。事务提交后,创建的read_view对象将被销毁。
有三个关键字段用于判断记录的可见范围,分别是trx_ids,low_limit_id,up_limit_id。
- trx_ids:记录活跃的其他事务的id集合;
- low_limit_id:trx_ids中最大的事务id+1,即系统中最近一个尚未分配出去的事务id;
- up_limit_id:trx_ids中最小的事务id。
ct_trx指当前记录的事务id,只有ct_trx<up_limit_id(表示该记录在当前事务开始前已经commit),以及事务id不在trx_ids列表中时,才会返回数据。
3.总结
-
设置并查看自动提交,MySQL默认为自动提交(autocommit=1):
set autocommit = 0;
SELECT @@autocommit;
-
设置隔离级别并查看当前隔离级别,MySQL默认为RR隔离级别:
set session transaction isolation level REPEATABLE read;
SELECT @@tx_isolation
-
查看事务相关的内容:
SHOW ENGINE INNODB STATUS;
-
read view对象在第一次查询时候产生(RR隔离级别下,RC隔离级别下每次查询都产生新的read view对象);
-
事务id不是在begin的时候分配的,进行具体的操作时候才会分配,可以通过查询下面的表来监控:
select * from information_schema.INNODB_TRX;