前面说了当设置的buffer_pool_size在1个G内,则不管如何设置,buffer_pool_instances都是一个,当在1个G以上,mysql才支持多个instances设置,每个都有自己独立的链表,多线程的情况下互不干扰运行。
Show engine innodb status\G
磁盘太慢,内存很有必要,buffer_pool在mysql启动的时候会向系统申请连续的内存空间,buffer_pool_instances 和buffer_pool_chunk_size这几个参数是倍数关系,设置的时候,mysql为了防止浪费内存出现碎片,自动会平衡他们的参数。
为了方便管理,里面有free链表,flush链表,lru链表,
Free链表就是申请空闲的缓存页,flush链表就是修改之后的数据,需要更新到磁盘上的,lru链表又分为young区域和old区域,这里面的数据代表后 使用数据。Select查询过程是先从磁盘吧数据放入buffer pool缓存页,有自己的控制块,吧控制块放入old区域,如果在buffer_old _block_time,初次和后一次访问超过这个时间,则会吧数据放入young,这样可以解决全表查询数据太大导致热数据被内存释放,也可以防止预读。
链表里面数据那么多怎么查询呢,通过hash表来查询,key是表空间id+页号,value就是缓存页。
为什么要事务?
我们先创建一个表
mysql> create table account(
-> id int not null auto_increment comment '自增id',
-> name varchar(100) comment '客户名称',
-> balance int comment '余额',
-> primary key (id
-> )engine=Innodb charset=utf8;
Query OK, 0 rows affected (0.04 sec)
+----+--------+---------
| id | name | balance |
+----+--------+---------
| 1 | 狗 | 11
| 2 | 猫 | 2
+----+--------+---------+
从上我们可以看到狗有11元,猫有2元,现实生活中,如果猫向狗借10元钱,那么够会变成1元,猫变成12元。那这两个操作在代码里运行其实执行两个sql语句。
UPDATE account SET balance = balance - 10 WHERE id = 1;
UPDATE account SET balance = balance + 10 WHERE id = 2;
但如果执行到一半的时候,断电了或者系统宕机,或者各种原因导致接下来一半不执行,狗的11元减少成功,猫但是还是显示2元,那么整个数据就会乱套。怎么能保证这些和现实中保持一致呢,于是要把现实中的规则带入到代码。
原子性(Atomicity)
现实中,两个人的转账操作是不可分割的,要不压根没转过,要不转账成功,不能一个人转账成功,另一个人没有收到钱。Mysql吧这种要么做就做完整的规则叫做原子性(Atomicity)。但现实中不可分割的操作,在数据库里可能要执行多次,比如两个sql,比如 缓存页的脏数据还没有刷新到磁盘上,要命的是,任何一个步骤错了,都会导致操作执行不下去,就会导致猫收不到钱。为了保证mysql数据库的原子性,mysql费尽心机吧已经操作的数据如果异常,就恢复到之前的数据,这是我们后面需要仔细唠嗑的回滚。
隔离性(isolation)
现实中两个人转账是互不干扰的,比如狗向猫转账两次5元,那么猫肯定会多10元,狗肯定少10元,那么代码中的过程是什么呢?
读取狗的金额,read(A)
狗的金额-5,A = A-5
吧狗的金额刷新到磁盘,write(A)
读取猫的金额,read(B)
猫的金额+5, B =B+5
吧猫的金额刷新到磁盘,write(B)
现在要操作两次,如果按顺序操作,比如1~6执行完之后,在执行1次1~6的步骤,这样是没有问题的,猫会+10,狗会减少10。
但很不幸的是,数据库真实的操作是这样的,
事务1:read(A)
事务2:read(A)
事务1:A = A-5
事务1:write(A),这时候A是6
事务1:read(B)
事务1:B=B+5
事务1:write(B),这时候b是7.
事务2:A = A-5,
事务2:write(A),这时候A还是6
事务2:read(B)
事务2:B=B+5
事务2:write(B) 这时候b是12
对于上面那种情况,如果猫加了10元,而狗减了5元,那么银行不是亏本了吗,所以mysql在每个事物之间让他们隔离开,互不干扰。
一致性(Consistency)
我们的生活有形形色色的约束,比如身份证号码不能重复,高考分数目前只能在0~750之间,红绿灯只能有三种颜色,买东西时候单价不能为负数等等,只有符合这些约束才有效,比如有人跟你说今天开车看到个蓝色的红绿灯,你一听就知道是假的。所以mysql数据库也是有约束性的。
其实可以从两方面努力,数据库本身能给我们保证约束性,比如触发器检测金额不能小于0。但这种一般都是不可取的,实际的业务场景里,我们都是通过程序员,因为更改数据库的时候检测是不是金额大于0是非常耗时的,但如果在代码里判断就非常简单,只要在编写业务的时候加个>0的判断就好。
前面的原子性和隔离性,对一致性也有很大的影响,如果原子性 和 隔离性不能保证,那么数据都是错的,根本就不可能保证一致性。
但原子性和隔离性一定满足,就能保证一致性吗,这又不一定,因为如果金额成为了负数,这也是不能满足一致性约束的。
持久性(Durability)
当我们现实生活中,发生借钱事件后,结果将会的保存下来,所以在mysql中也是如此,比如狗向猫转账,成功后,猫的账单又回到2,恢复到转账前的样子,那样实不可取。
所以持久性意味着数据必须在磁盘上保存。
事务的概念
综上所述,Atomicity,Isolution,Consistency,Durability,合在一起就是ACID,mysql为了方便,直接把这四个统一称为transaction。
事务大致划分四个状态:
活动的(active):事务对应的数据库操作正在执行中,表示该事务活动的状态。
部分提交的(partially committed):事务的后一个操作完成,但因为事务都在内存里进行,还没有刷新到磁盘上,这种称为部分提交。
失败的(filed):当事务在活动的,部分提交的时候遇到错误,如数据库错误,或者断电等,这时候事务就在失败状态。
终止的(aborted):当在活动和部分提交之后,出错怎么办呢,失败之后就终止,并且mysql会吧当前的数据恢复到操作前的状态,我们叫这个为回滚。
提交的(commited):如果成功呢,则就持久化到磁盘上。
文章来源:知乎平台 原文地址:https://zhuanlan.zhihu.com/p/417598239