数据库知识

207 阅读5分钟

1.MVCC

两个session.png 案例:session1修改了一条记录,没有提交,于此同时,session2来查询这条记录,返回多少?session1提交后,session2再次提交查询出来又是多少呢?

读未提交:第一次20,读到脏数据了,第二次20 读已提交:第一次10,第二次20 可重复读和串行化:第一次10,第二次10

读已提交好理解符合正常认知,可重复读解决了不可重复读,关键是这个不可重复读是问题吗?

不可重复读:

读已提交中,session2第一次读到的是10,第二次读到的是20,如果是显示界面上你一次数据库会话的结果最好不要变,多次查询都一样。如果你要看最新数据,开启一个新的数据库会话。如果你是要在一个数据库会话里相同的查询查多次进行处理统计可能会出现问题,所以才有可重复读保证读任意次都是一样的结果。

mvcc原理:
mvcc叫多版本并发控制,也就是数据库他对于一条记录会维护多个历史版本,用指针将这些历史版本串起来。这些历史版本是存在undo日志文件里的。

再理解一个概念read view,他是一个数组,里面装的是当前系统活动的事务id。

可重复读是基于事务粒度的,读已提交是基于语句粒度的。
可重复读:在每个事务开始的时候,会将当前系统中所有活跃事务拷贝到read view里。
读已提交:在每个语句开始的时候,会将当前系统中所有活跃事务拷贝到read view里。

我们以可重复读为例:
当开始一个事务时,把当前系统中活动的事务id拷贝到read view里,我们将最小事务id记为tmin,最大事务id记为tmax。
当读到一行时,该行上当前事务id我们记为tid,如果他比tmin还小,显示该行,如果他比tmax还大,找到该行的下一个历史版本取出版本号赋值给tid,从新开始判断逻辑,如果他比tmin大比tmax小,看他是否在read view数组内,如果不在显示改行,如果在,找到改行的下一个历史版本取出版本号赋值给tid,从新开始判断逻辑。
流程图:

mvvc流程图.png

2. 数据库三种日志

redolog:

重做日志是InnoDB存储引擎独有的,如果Mysql实例挂了,重启时,InnoDB存储引擎会使用redolog恢复数据,保持数据的完整性。

在某个数据页上做修改操作,修改会记录到重做日志缓存里,接着会被持久化到redolog文件里。

持久化策略:
innodb_flush_log_at_trx_commit:
值为0:每次事务提交时不进行持久化,指望后台线程,每隔1秒,会将redo log 缓存里的内容写到page cache里,然后持久化,要么就是redo log缓存空间快到一半时,持久化。
问题:事务没提交redo log缓存内容就被持久化到redo log里,还有mysql挂机了,可能会有1秒的redo log缓存内容丢失。
值为1:每次事务提交时都进行持久化(默认值)
只要事务提交成功,redo log缓存内容就会被持久化到redo log文件里不会有任何数据丢失,如果事务执行期间mysql挂了,redo log缓存丢失,但是事务没有提交,所以redo log缓存丢了也不会影响。
值为2:每次事务提交时都只把redolog缓存内容写入到page cache里
只要事务提交成功,redo log缓存中内容就会写入page cache,如果mysql挂了不会有影响,如果操作系统挂了会有1秒数据的丢失。

redo log文件不止一个,是以一个日志文件组的形式出现,每个redo log大小一样,循环进行写数据。
当系统空闲时或者redo log文件存满时会将redo log数据更新到数据文件中,擦除redo log内容。

binlog:

格式有三种:
statement:原始sql语句
row:如果是now语句,同步数据时执行会时间不一致,所以格式是包含操作的具体数据(默认格式)
mixed:对前两种的中间方案,msql会判断sql语句是否会有问题,如果是就用row格式,如果没有就有statement格式

持久化策略:
sync_binlog:
值为0(默认值):
事务执行中,会先把日志写到binlog缓存,事务提交时,再把binlog缓存中内容写入到page cache中,再由系统决定什么时候持久化到binlog文件中。
值为1:
事务执行中,会先把日志写到binlog缓存,事务提交时,再把binlog缓存中内容写入到page cache中,再持久化到binlog文件中。
值大于1,记为n:
事务执行中,会先把日志写到binlog缓存,事务提交时,再把binlog缓存中内容写入到page cache中,提交事务累计到n,再持久化到binlog文件中。

undolog:

innoDB日志,用于回滚事务。

当执行更新操作时,事务还未提交时,会对反操作sql进行备份,备份到undo缓存,再持久化到undo log中,undo log中保存了之前反操作sql,当事务回滚时就会利用undo log进行回滚。