绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
transaction (1)—mysql进阶(五十七)
2023-02-06 09:49:55

前面说了当设置的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

分享好友

分享这个小栈给你的朋友们,一起进步吧。

MySQL干货资料
创建时间:2020-05-06 14:18:32
每天都有干货输出哦
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

技术专家

查看更多
  • 飘絮絮絮丶
    专家
戳我,来吐槽~