事务特性(ACID)
-
原子性
-
一致性
-
隔离性
-
持久性
日志(innodb)
-
binlog日志
binlog记录了数据库表结构和表数据变更,它存储了每条变更的sql。binlog主要用来复制和恢复数据,例如在主从复制中,以及数据库崩溃恢复。
-
redo日志
事务提交后,需要把数据保存到磁盘,如果每次都刷盘,会影响效率。所以将修改行为先写到redo日志中,再定期将日志刷到磁盘中,redolog记载的是物理变化(xxxx页做了xxx修改)。
-
undo日志
事务未提交时,会将修改前的旧版本存放到undo日志,事务回滚时,利用undo日志,撤销未提交事务对数据的影响。
存储undo的地方就是回滚段。
insert操作,undo直接存数据的pk(row_id),回滚直接删除delete/update,记录旧数据row,回滚直接恢复
binlog和redo log 区别
- binlog记载的是
update/delete/insert
这样的SQL语句,而redo log
记载的是物理修改的内容(xxxx页修改了xxx)。
- redo log的作用是为持久化而生的。写完内存,如果数据库挂了,那我们可以通过redo log来恢复内存还没来得及刷到磁盘的数据,将redo log加载到内存里边,那内存就能恢复到挂掉之前的数据了。
binlog的作用是复制和恢复而生的。
mysql操作数据,会先写入redo log再写入 binlog,如果其中任何一个失败,就会回滚
隔离性
-
脏读。事务T1修改某条数据,事务T2读取该值,T1由于某种原因导致回滚,导致T2所读的数据是无效数据。
-
不可重复读。一个事务范围内,两个相同的查询却返回不同的值。由于在事务范围内,有其它事物修改了数据导致。
-
幻读。与不可重复读非常类似,指一个事务范围内,两次相同的查询,第二次比第一次少或多数据。
-
InnoDB四种事务隔离级别实现原理
-
read uncommitted
select语句不加锁,并发最高,一致性最差。
-
read commotted
普通读是快照读
加锁的select, update, delete等语句,除了在外键约束检查(foreign-key constraint checking)以及重复键检查(duplicate-key checking)时会封锁区间,其他时刻都只使用记录锁;此时,其他事务的插入依然可以执行,就可能导致,读取到幻影记录。
-
repeatable read
InnoDB行锁是通过给索引上的索引项加锁的,InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则InnoDB将使用表锁。另外,无论是使用主键索引、唯一索引或普通索引,InnoDB都会使用行锁来对数据加锁;
如果MySQL认为全表扫描效率更高,比如对一些很小的表,它就不会使用索引,这种情况下InnoDB将使用表锁而不是行锁。
范围查询条件,会使用间隙锁与临键锁,锁住索引记录之间的范围。
-
serializable
所有select语句都会被隐式的转化为select ... in share mode,如果有事务正在修改该行,那么读会阻塞,这是并发最低,一致性最好的
锁
-
乐观锁
具体实现是,表中有一个版本字段,第一次读的时候,获取到这个字段。处理完业务逻辑开始更新的时候,需要再次查看该字段的值是否和第一次的一样。如果一样更新,反之拒绝。之所以叫乐观,因为这个模式没有从数据库加锁,等到更新的时候再判断是否可以更新。
-
悲观锁
悲观锁则是直接加锁。
小知识:
innodb只有通过索引检索数据,才会使用行锁,否则使用表锁。
innodb锁
-
自增锁
自增锁是一种特殊的表级别锁,专门正对插入包含自增的列,如果一个事务正在插入数据,那么其它事务的插入必须等待。
-
共享/排它锁(行级别)
读锁(S锁),写锁(X锁)。写锁是排它锁。读读可以并行,写写、读写是互斥。
-
意向锁(行级别)
意向锁是指,在某个时刻,事务可能要加共享/排它锁,先提前声明一个意向。意向锁分为意向共享锁(IS);意向排它锁(IX),意向锁之间不互斥。
S X
IS 兼容 互斥
IX 互斥 互斥
-
插入意向锁
上面提到插入有自增列的数据,有自增锁,如果插入没有自增列的数据,则是插入意向锁,它是间隙锁的一种,实施在索引上,专门正对insert操作。
-
记录锁
封锁索引记录,例如select * from user where id = 1 for update;
-
间隙锁
封锁第一条索引之后或者最后一条索引之前的数据。
例如:select * from user where id between 1 and 10 for update; 会锁定id 1-10的所有行,防治出现幻影数据,假如插入了一条id=5的记录,那么执行相同的sql会发现多了一条记录,出现幻影数据,所以这么做防治了不可重复读。
-
临键锁
临键锁,是记录锁与间隙锁的组合,它的封锁范围,既包含索引记录,又包含索引区间。临键锁会封锁索引记录本身,以及索引记录之前的区间。避免幻读。