• Mysql面试(事务)


    今天来聊聊mysql面试里常见的事务的知识(这里所说的都是Innodb下的事务,MyISAM他也不支持事务不是)

    什么是事务?为什么需要事务? 

    所谓事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。 为什么需要事务呢?例如 :银行转账的问题,从一个账号扣款并使另一个账号入账,这两个操作要么都 执行,要么都不执行。所以,应该把它们看出一个事务。

    事务的四大特性 (ACID),问你什么是ACID要能说出来

    • 原子性(atomicity)
    • 一致性(consistency)
    • 隔离性(isolation)
    • 持久性(durability)

    大概聊聊各个都是什么意思,网上资料也很多可以自行查阅

    • 原子性:一个事务作为不可分割的最小单元,一个事务里面的所有操作要么全部成功,要么全部失败(即:将多个操作数据库的动作捆绑在一起。如将多个修改表数据的操作捆绑在一起,只有当所有的修改操作都执行成功后,这个事务才视为成功;否则其中一个修改操作出现错误时,整个事务都将视为失败,并且在错误出现前执行成功的所有操作都需要回滚为此前未修改时的状态)
    • 一致性事物结束后系统状态是一致的,数据不能平白无故的产生,也不能平白无故的消失(如:微信好友间的转账服务,你的朋友向你转账100元,此时你的账户余额少了100,你的朋友多了100,但你们最终的余额总和是与转账前保持一致的~!不能是你转了100之后,你朋友那只多了50,这样前后不一致)
    • 隔离性一个事务所有的操作,在最后Commit(提交)之前,所有修改对其他事务不可见(使用过Git的读者朋友们都知道,在与别人一起合作写代码时,双方都需要在远程的代码仓库拉取中代码保存在自己的本地仓库,并且在各自的本地仓库对代码进行编写或修改,最后再将本地仓库写好的代码上传至远程仓库中。在这个过程里,本地仓库代码在没有上传到远程仓库前,双方都是无法得知对方本地仓库代码做了什么变动的,二者的本地仓库都是相对隔离开来的)
    • 持久性当事务提交后,数据应该永久被保存到数据库中,即使发生了灾难性后果,数据也不会丢失(简单说就是,将数据存入到磁盘中~!)

     下面聊聊开启事务的步骤

    1. #步骤一:开启事务(可选)
    2. start transaction;
    3. 或者begin; 我选begin哈哈哈因为简单
    4. #步骤二:编写事务中的sql语句(insert、update、delete
    5. #步骤三:结束事务
    6. commit; #提交事务
    7. # rollback; #回滚事务:就是事务不执行,回滚到事务执行前的状态

    注意:开启事务后执行修改命令,变更会维护到本地缓存中,而不维护到物理表中,好比操作了一个虚拟的数据库一样。

    执行commit之后,才是将缓存中的数据变更维护到物理表中

    比方说我开启事务之后,新增了一条数据,然后写一个修改的sql执行之后发现自己修改错了,这时候rollback回滚一下,这时候就回到你新增完数据的那个阶段了,你再重新去写正确的修改的sql就可以了,最后commit之后,中间写的所有sql才会真正的执行到数据库。

    最后着重来聊聊隔离性的内容

    在数据库中不可重复读和幻读到底应该怎么分? - 知乎 (zhihu.com)

     事务并发时可能会出现一些问题

    比方说两个人同时操作这个数据库,对表的数据进行修改,可能出现A在操作表中的数据,B也同样在操作表,那么就会出现并发问题,对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,如果没有采用必要的隔离机制,就会发生以下各种并发问题。

    1. 脏读:脏读是读到了别的事务回滚前的脏数据。比如事务B执行过程中修改了数据X,在未提交前,事务A读取了X,而事务B却回滚了,这样事务A就形成了脏读。A读到的数据就是临时且无效
    2. 幻读:对于两个事务A,B,A在表中读取了一个字段,然后B又在表中插入了一些新的数据时,A再读取该表时,就会发现神不知鬼不觉的多出几行了,A就会觉得很突兀,不知道这些数据是从哪来的,这就是幻读
    3. 不可重复读:事务A查询了一条数据后,事务B对该条数据进行修改,此时当事务A再次查询该数据时,得到的结果与第一次查询的不一致

    针对这些问题,我们就需要采取一些手段去避免,mysql数据库系统提供了四种事务的隔离级别,用来隔离并发运行各个事务,使得它们相互不受影响,这就是数据库事务的隔离性。

    事务的隔离级别(补充戳(ee  (另一个  )

    • READ UNCOMMITTED 未提交读
    • READ COMMITTED 提交读
    • REPEATABLE READ 可重复读
    • SERIALIZABLE 可串行化 

    mysql默认的是第三个级别 可重复读,一般来说第二个和第三个用的最多

    在未提交读下,也就是级别最低,并发操作时A对表数据进行的任何更改,即使还没有commit提交,B也立马就可以看到,几乎就是共享数据了,互相是透明的,在此级别下脏读、幻读、不可重复读等问题都会出现

    在提交读下,A对表数据做的修改在还没commit的时候,B看不见任何改变,但只要A commit提交了,B就可以看到了。此级别下解决了脏读的问题,存在幻读和不可重复读(同时,这也是大多数数据库默认的事务隔离机制)

    在可重复读下,A对表数据做的修改,在commit之后A事务结束,数据已经改了,但是B这个事务执行过程中看到的仍然是之前表未改的状态,(就是感觉很怪,明明数据改了但是我就是读不到,感觉出现了幻觉,这就是有幻读问题)此级别下解决了脏读和不可重复读的问题,但仍然存在幻读的问题(同时,这是MySQL默认引擎InnoDB引擎的默认事务隔离级别

    在可串行化下,此级别下脏读、幻读已经不可重复读等问题都将不复存在,在此级别下每条操作命令都必须等到上一条命令执行完毕后才可以开始执行,此时我们的数据库可以看成是一个单线程的程序,数据是绝对安全的,但却严重影响程序的运行效率,只有但数据安全性的要求大大高于运行效率要求时我们才使用该隔离级别

    下面是一些有关mysql隔离相关的命令

    查看当前会话隔离级别:

    SELECT @@SESSION.transaction_isolation;

     查看系统隔离级别:

    SELECT @@GLOBAL.transaction_isolation;

    设置隔离级别:

    1. # 设置全局隔离级别
    2. set global transaction isolation level REPEATABLE READ;
    3. set global transaction isolation level READ COMMITTED;
    4. set global transaction isolation level READ UNCOMMITTED;
    5. set global transaction isolation level SERIALIZABLE;
    6. #设置会话隔离级别
    7. set session transaction isolation level REPEATABLE READ;
    8. set session transaction isolation level READ COMMITTED;
    9. set session transaction isolation level READ UNCOMMITTED;
    10. set session transaction isolation level SERIALIZABLE;

    对于MySQL就讲到这里啦,若文章存在错误还望各位读者指出~

  • 相关阅读:
    VirtIO
    tcp checksum 0xffff instead of 0x0000 see rfc 1624
    TypeScript 高级类型-详解
    [安洵杯 2019]easy_web md5强碰撞 preg_match绕过
    LabVIEW样式检查表3
    python numpy数组
    如何使用 Selenium 实现自动化操作?
    LeetCode 0289. 生命游戏
    grpc protoBuf 编码/解码原理
    分布式 PostgreSQL 集群(Citus),分布式表中的分布列选择最佳实践
  • 原文地址:https://blog.csdn.net/weixin_51609435/article/details/127728900