# 知识点3mysql
悲观锁-一锁二查三更新pcc,pessimistic concurrency control
乐观锁-在数据上加一个版本号或者时间戳occ,optimistic concurrency control
acid:
A: 原子性(atomicity)
C: 一致性(consistency)
I: 隔离行(isolation)
D: 持久性(durability)
MySQL事务的实现
隔离性通过Mysql InnoDB锁就可以实现,
原子性、一致性、持久性通过数据库的redo和undo来完成
对于事务操作的统计
QPS:question per second,每秒请求数
TPS:transaction per second,每秒事务处理的能力
计算TPS的方法是(com_commit+com_rollback)/time,用这种方法的前提是,所有的事务必须都是显式提交的。
SQL标准定义的四个隔离级别为:
1、READ UNCOMMITED
2、READ COMMITED
3、REPEATABLE READ
4、SERIALIZABLE
1, READ UNCOMMITTED(未提交读)
事务中的修改,即使没有提交,对其它事务也是可见的. 脏读(Dirty Read).
2, READ COMMITTED(提交读)
一个事务开始时,只能"看见"已经提交的事务所做的修改. 这个级别有时候也叫不可重复读(nonrepeatable read).
3, REPEATABLE READ(可重复读)
该级别保证了同一事务中多次读取到的同样记录的结果是一致的. 但理论上,该事务级别还是无法解决另外一个幻读的问题(Phantom Read).
幻读: 当某个事务读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录.当之前的事务再次读取该范围时,会产生幻行.(Phantom Row).
幻读的问题理应由更高的隔离级别来解决,但mysql和其它数据不一样,它同样在可重复读的隔离级别解决了这个问题.
也就是说, mysql的可重复读的隔离级别解决了 "不可重复读" 和 “幻读” 2个问题. 稍后我们可以看见它是如何解决的.
而oracle数据库,可能需要在 “SERIALIZABLE ” 事务隔离级别下才能解决 幻读问题.
mysql默认的隔离级别也是: REPEATABLE READ(可重复读)
4, SERIALIZABLE (可串行化)
强制事务串行执行,避免了上面说到的 脏读,不可重复读,幻读 三个的问题.
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set
mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ |
+-----------------------+
1 row in set
mysql> show variables like 'innodb_support_xa';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| innodb_support_xa | ON |
+-------------------+-------+
1 row in set
MVCC(Multi-Version Concurrency Control) 多版本并发控制
MVCC的实现,是通过保存数据在某个时间点的快照来实现的.
InnoDB的MVCC是通过在每行记录后面保存2个隐藏的列来实现的,一列保存了行的创建时间,一列保存了行的过期时间(或删除时间).但它们都存储的是系统版本号
MVCC最大的作用是: 实现了非阻塞的读操作,写操作也只锁定了必要的行.(并行读,行锁)
MYSQL的MVCC 只在 read committed 和 repeatable read 2个隔离级别下工作.
InnoDB 锁的算法
5.1 Record Lock: 单个行记录的锁
5.2 GAP Lock: 间隙锁,锁定一个范围,但不包含记录本身.
5.3 Next-Key Lock: Gap Lock+Record Lock 锁定一个范围并锁定记录本身.
下面的2句话是InnoDB在不同隔离级别下产生"不可重复读" 和 "幻读" 和解决它 的根本原因:
InnoDB存储引擎默认的事务隔离级别(repeatable read)下,采用的是 Next-Key Locking的方式来加锁.
read committed隔离级别下采用的是: Record Lock 的方式来加锁.
总结:
1, InnoDB用MVCC来实现非阻塞的读操作,不同隔离级别下,MVCC通过读取不同版本的数据来解决"不可重复读" 的问题.
2, InnoDB的默认隔离级别解决2个问题,"不可重复读" 和 "幻读", oracle需要在串行读中解决"幻读"问题. InnoDB的实现方式和一般隔离级别的定义不一致.
3, InnoDB的默认隔离级别采用Next-key Lock(间隙锁) 来解决幻读问题. 而 read committed隔离级别采用Record锁,因此会产生"幻读"问题.
4, InnoDB的存储引擎不存在锁升级的问题(太多的行锁升级为表锁),来降低锁的开销. 因为不是根据记录来产生行锁的,根据页对锁进行管理.
事务的分类
1.1 扁平事务
要么都执行,要么都回滚,InnoDB最常用,最常见的事务.
1.2 带有保存点的偏平事务
事务的操作过程有 begin, A, B, C, D, commit 几个过程,那么带有保存点的扁平事务过程大致如下:
begin--> 隐含保存点1(save work 1)-->A-->B(save work2)-->C-->D(rollback work2) -->commit
上述过程中如果遇到rollback work2, 只需要回滚到保存点2,不需要全部回滚.
简单来说,带有保存点的扁平事务就是有计划的回滚操作。
保存点是容易失的(volatile), 而非持久的.系统崩溃,所有保存点都将丢失.
1.3 链事务
链事务提交一个事务时,释放不需要的数据对象,将必要的上下文传递给下一个要开始的事务. 下一个事务可以看到上一个事务的结果.
带有保存点的偏平事务可以回滚到任意正确的保存点,链事务只能回滚到当前事务.
扁平全程持锁,链事务在commit后释放锁.
链事务如: T1->T2->T3
1.4 嵌套事务
可以理解为一颗事务树,顶层事务控制着下面的子事务. 所有的叶子节点是扁平事务,实际工作是由叶子节点完成的.
1.5 分布式事务
分布式环境下运行的扁平事务.
InnoDB支持上述除嵌套事务以外的所有事务类型.
总结
1, redo log(事务日志)保证事务的原子性和持久性(物理日志)
2, undo log保证事务的一致性,InnoDB的MVCC也是用undo log来实现的(逻辑日志).
3, redo log中带有有checkPoint,用来高效的恢复数据.
4, 物理日志记录的是修改页的的详情,逻辑日志记录的是操作语句. 物理日志恢复的速度快于逻辑日志.