MySQL数据库的事物详解

虽然我标题说了是详解,但是肯定不可能特别详细

一、事物的特点以及隔离性

    ACID:A--原子性--事物在执行时,要不就执行成功,要不就执行失败然后回滚,这就是原子性

                C--一致性--事物在执行前后,事物的状态是不会改变的

                I--隔离性--A事物在执行的时候,B事物是无法影响到该事物的执行的

                D--持久性--事物一旦被提交,就是永久的

了解了事物的四大特性之后,就得了解一下事物的隔离性了,因为MySQL的隔离级别会对应事物的隔离性,事物有三大隔离性

    我们以下图的数据库做为实例,主键索引

        

    注:众所周知,事物在没有提交/回滚的时候是不会释放的

    1、脏读:读取了事物还未提交过的数据

        我们先开启事物,数据库开始事物的方法我知道两种,一种是begin,一种是start transaction,很明显第一种好用,那么我们在第一个查询中先查询id为1的数据信息

        

        然后去第二个查询中修改id为1的数据

        

        可以看到我们读取的数据是已经变化了,但是当我们再次去第一个查询中查询id=1的这条数据时,我们发现数据并没有改变

                

        也就是说我们并没有使用我们修改后的数据,而是使用了修改之前的数据

    2、不可重复读:读取了两次数据,但是第一次读取的数据是未改变之前的数据,而第二次读取的数据是另外事物修改过后的数据,两次数据读取不一样

        不可重复读其实和脏读差不多,区别就在于脏读是事物还没有commit时读取,而不可重复读是事物commit过后读取(代码和脏读差不多,区别就在于第二次修改的时候我们需要commit,然后再去查询,这个查询是第一个事物的查询)

        

    3、幻读:读取了两次数据,但是第二次数据读取会出现一条或多条第一次读取未出现过的数据(幻读的前提条件是进行了区间查询/范围查询)

        第一个事物中我们去查询id大于9的数据

        

        第二个事物中我们插入一条id为11的数据,查询发现已经修改了

        

        这时候再次查询id大于9的数据

        

        我们发现多了一条数据,这就是幻读

二、MySQL的隔离级别

接下来我们就可以去看看MySQL的四大隔离级别了

    1、未提交读:没有解决任何一种隔离问题

    2、已提交读:解决了脏读的问题

    3、可重复读:解决了脏读以及不可重复读的问题

    4、串行化:解决了脏读、不可重复读以及幻读的问题

    注:按照java的或者说是所有语言的特性,越是完美的方案,那么运行的效率肯定是越低的,而数据库类别不同,它的默认隔离级别是不同的

三、MySQL类别

    数据库的类别有ISAM、MYISAM、Innodb等等,其中最常见的就是Innodb以及MYISAM

        MYISAM只支持表锁,不支持外键,事物不安全,优点就是在大量查询的时候使用比较好,并且MYISAM使用的是非聚集索引,而对比MYISAM来讲,Innodb不仅支持表锁,还支持行级锁,支持外键,事物方面更是优化的很好,在update以及insert的时候用Innodb是更加方便,缺点是对高并发可能不是很好,使用的是聚集索引

    注:非聚集索引指的是索引中存储的是索引本身以及数据所在的物理位置,在非聚集索引中辅助索引和主键索引是没有太大区别的,最大的区别就是辅助索引可以有重复数据,出现重复数据的时候只是增加了一张索引表,而聚集索引指的是索引中存储的是索引本身以及数据,聚集索引的索引就有很大区别了,所有辅助索引存储(唯一/普通/组合/全文--需要注意的是全文索引在老版本中的Innodb是不存在的,最低版到了5.6开始支持全文--索引)的都是索引本身加主键

四、Innodb行锁详解

    1、Innodb锁的类别,包括

    共享锁:也成为读锁,意思是当事物中加入共享锁的时候,其他事物无法进行任何修改操作,但是可以进行查询操作

        第一个事物查询id=1的数据,并加入共享锁,共享锁是在语句后面加上 lock in share mode

        

        第二个事物去

            查询数据:没有任何影响

            

            查询数据加上排它锁:一直等待

            

            查询数据加上共享锁:无任何影响

            

            注:从这几条数据我们可以分析出来,共享锁是排斥排它锁的

            修改数据:一直处于等待状态,没有继续执行,被行锁阻塞

            

            添加数据:执行成功,也就是添加数据是没有问题的,并么有影响到行锁

            

            删除数据:一直处于等待状态,没有执行成功

            

    排它锁:

        也可以叫做写锁,就是在事物中加入排它锁,那么其他的事物就不可以进行任何操作,包括读操作,当然因为insert并没有涉及行锁所在的位置,所以并没有影响,还是可以继续添加数据,排它锁代码是 for update

        第一个事物修改id=1的数据,并加入排它锁

        

        第二个事物去

            查询数据:没有任何影响

            

            查询数据加上排它锁:一直等待

            

            查询数据加上共享锁:一直等待

            

            注:从前面三条数据以及对共享锁的分析可以总结出共享锁和排它锁是互相排斥的

            修改数据:一直处于等待状态,没有继续执行,被行锁阻塞

            

            添加数据:执行成功,也就是添加数据是没有问题的,并么有影响到行锁

            

            删除数据:一直处于等待状态,没有执行成功

            

    意向共享锁、意向排它锁属于表锁,不需要也不可能会被开发人员使用修改

    注:因为mysql会在语句进行添加、修改以及删除的时候自动添加排它锁,这个就不给大家演示了

    既然已经知道了共享锁以及排它锁的区别或者使用方式,那么我们就该想了,共享锁以及排它锁是怎么实现的处理隔离问题的呢,用的什么算法呢,这个就是下面要讲的

    2、 Innodb行级锁的算法

    

        a、临近锁:Innodb默认使用的就是临近锁的分隔方法,他是间隙锁+记录锁,每条数据的前面知道碰到另外一条数据为止的区间进行加锁,不包括前面的数据(无穷,1],(1,3],(3,7],(7,10],(10,12],(12,15],(15,无穷]就是他的分隔方法,比如我们查询id>11并且id<13的数据,按照我上面的分隔区间,那么当我们加上排它锁的时候,(10,15]都没有办法进行加锁操作

         事物1加上排它锁

        

        事物2对10操作,可以看到是没有影响的,也就是满足了左开的原则

        

        事物2对11操作,可以看到我们是没有办法进行添加操作的,因为11被锁住了

        

        那么我们再来看看对13,14,15,16进行操作能不能成功

        

        

        可以看到除了16都被阻塞,所以就应征了我们上面的说法,因为我们查询的是11-13中间的数据,所以,从11之前的第一条数据截止13之后第一条数据(10,15]是被锁住的,但是这样的话,我们希望去操作15的时候就会出现问题,因为我们需要的仅仅是11-13之间加锁,并不希望对15进行加锁,所以就出现了间隙锁这个概念

        b、间隙锁:是对临建锁的一种优化,间隙锁可以很好的解决隔离问题中幻读的问题,所以Innodb的优点之一就在这体现了出来,因为如果使用串行话去进行事物隔离是可以解决幻读问题,但是效率低下,而使用Innodb可以不用担心这个问题,直接使用可重复度的隔离就行了

        

        同样的我们使用这个表,当我们查询的范围中没有任何一条记录的时候,临建锁就会退化成间隙锁

        事物1对13进行加锁,因为没有数据,所以查询出来的是空值

        

        事物2对12,13,15进行操作

        

        

        由此可见,我们的间隙锁区间就是我们上面所说的,不包括区间两端的记录,并且区间中间没有任何记录

        注:前两算法是在使用范围查询的时候会出现的,并且这三个算法都是MySQL自动进行转换的我们不需要手动操作,但是需要注意的是间隙锁比较容易出现死锁的状态,所以我们最好还是从优化sql语句入手

        c、记录锁:只会锁定当前的记录行,其余行不受影响

五、行锁锁定问题

    我们已经知道了行锁锁定的是表的行记录,那么行锁究竟锁定的是什么呢,是clown,还是索引,还是主键索引

    我们就来分析一下

    1、我们先什么也不加,包括主键 

    

    事物1加入排它锁

    

    事物2进行修改操作,先修改3,这个毫无疑问是不可以的

    

    然后操作4,按照我们上面的写法就是加上主键之后,按理是成为了记录锁,所以不会影响对除了3以外的其他记录产生锁,但是事实是也有锁,那么我们就可以先猜测是因为主键的原因

    

    再来看看操作5会不会有影响,我们会发现,连5都被加上了锁,很难受,但是没办法,因为mysql就是这样,如果没有找到加锁的条件,那么会默认在每一行记录后面加上聚集索引,然后,顺便将每一条聚集索引都加上锁,因为我们刚才也说了是主键的原因,那么现在我们就可以猜想是因为索引的原因

    

    2、接下来我们进行第二次试验

    我们加上一个唯一索引,因为上面的例子都是用的主键索引,所以我就不写主键的例子了

     

    

    同样,我们重复第一次试验步骤

    事物1加入排它锁,因为我们在name上加的唯一索引,所以加锁也是根据name来加

    

    事物2对name = 3的记录操作

    

    对name  = 4的记录操作,按照我们之前的想法,只要加上索引,那么就可以了,确实是可以了,但是有点超过了我们的想像范围

    

    那么我们再看看对name = 5 的记录会不会有影响,我们发现,也是有影响的,这其实和什么也不加mysql默认的聚集索引一样了啊,所以我们推测,其实最重要的是主键索引,行锁主要的依据条件就是主键索引

    

    那么为什么唯一索引不可以呢,这是因为唯一索引其实根本上还是去查找主键索引,唯一索引等辅助索引储存的只有本身以及主键,唯一索引储存的除了本身和主键之外还有数据,所以当唯一索引去找主键索引没有找到的时候,mysql就会去创建默认聚集索引,那么其实就和什么索引都不加是一样了,也就是说,行锁其实就是根据主键索引进行判断的

    到此为止我能想到的已经说得差不多了,希望能帮助到大家

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
随着微信小程序的不断发展,微信小程序云函数也逐渐成为了开发者们的首选。在小程序云函数中,使用MySQL数据库是个常见的需求。下面就给大家详细介绍在微信小程序云函数中如何使用MySQL数据库。 首,我们需要在小程序开发者工具中初始化云函数,并在云函数中安装mysql模块。安装完成后,我们需要在云函数的入口文件中引入mysql模块和配置数据库连接。 const mysql = require(‘mysql’); const connection = mysql.createConnection({ host : ‘xxx.xxx.xxx.xxx’, user : ‘root’, password : ‘root’, database : ‘test’ }); 以上是配置数据库连接的示例代码,其中host字段填写你的mysql数据库地址,user和password字段填写数据库用户名和密码,database字段填写使用的数据库名称。 接下来就可以在云函数中编写mysql相关的增删改查操作了。下面是示例代码: //查询 connection.query(‘SELECT * FROM users’, function (err, result) { if (err) throw err; console.log(result); }); //插入 let user = {name: ‘张三’, age: 18}; connection.query(‘INSERT INTO users set ?’, user, function(err, result) { if (err) throw err; console.log(result); }); //更新 let updateUser = {age: 20}; connection.query(‘UPDATE users set ? where name = ?’, [updateUser, ‘张三’], function(err, result) { if (err) throw err; console.log(result); }); //删除 connection.query(‘DELETE from users where age = 20’, function(err, result) { if (err) throw err; console.log(result); }); 以上代码中,我们分别实现了数据库的查询、插入、更新和删除操作。其中插入和更新操作的数据需要我们传入一个对象,表示要插入或更新的数据。实际应用中,需要根据情况自行调整。 最后需要注意的一点是,由于云函数每次内存释放后,连接都断开,所以在进行数据库操作时需要每次建立连接并且操作完成后及时断开连接,避免数据库连接过多导致性能下降。示例代码如下: module.exports = { getUserList: async (event) => { let userList = []; let connection = mysql.createConnection({ host : ‘xxx.xxx.xxx.xxx’, user : ‘root’, password : ‘root’, database : ‘test’ }); connection.connect(); userList = await new Promise((resolve, reject) => { connection.query(‘SELECT * FROM user’, function (error, result) { if (error) throw error; resolve(result); }); }); connection.end(); return { userList: userList }; } } 以上代码中,在getUserList方法中,我们在每次使用之前创建一个新的数据库连接,然后进行查询操作,最后断开连接。 总结:在微信小程序云函数中使用MySQL数据库,需要在云函数中安装mysql模块,并配置好数据库连接,然后就可以在云函数中编写相关的MySQL操作代码。注意每次操作完成后及时断开连接,避免连接过多影响性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值