美文网首页
mysql(一):mysql的一些基础常识

mysql(一):mysql的一些基础常识

作者: 骑着母猪砍大象 | 来源:发表于2018-12-18 13:29 被阅读92次

    转载请注明作者和出处https://www.jianshu.com/p/4bfbe89c9c1f

    作者简介: 一个本该成为游戏职业选手却被编程耽误的程序员


    线程

         mysql是线程级别的,每个客户端连接会在服务器进程中拥有一个线程,该线程只能轮流在某个cpu核心或者cpu中运行,服务器只会缓存线程,因此不会为每个新的链接创建新的线程或者销毁线程

        mysql的锁从功能上分为共享锁(shared lock)排他锁(exclusive lock),也可以称为读锁(read lock)写锁(write lock),顾名思义,读锁的是多个用户在读取同一个资源,互不干扰,写锁是排他的,也就是说一个写锁会阻塞其他写锁和读锁,也就是说,在一个用户(一个链接)执行写锁的时候,其他用户处于等待状态。
       注意,锁的各种操作都是需要消耗资源的,检查锁是否解除,释放锁,都会增加系统的开销。所以锁的数量和数据的安全性在大型项目中需要一个中间平衡点。

    锁的粒度

    锁的粒度在不同的存储引擎表现是不一样的。
       表锁(table lock)顾名思义,就是锁住整张表,其他连接不能进行任何操作,是开销最小的锁。
       行锁(table lock)顾名思义,就是锁住修改的数据,其他连接不能进行任何操作,是开销最大的锁。

    ACID的概念

    • 原子性(atomicity):不可切割的最小工作单元,一个事务一旦开始,要么就不做,要么全做,不可能停在中间环节,中间环节出错的话,会出现回滚成事务开始的状态,所有的sql语句就像没发生过一样;
    • 一致性(consistency):要么一起成功,要么一起失败;
    • 隔离性(isolation):一个事务在最终修改之前,其他事务是不可见的,并发执行的时候与其他事务相互隔离
    • 持久性(durability):也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。简单来说就是修改会保存到真正的数据库中

    隔离级别

    • Read Uncommitted(读取未提交内容)
      在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。
    • Read Committed(读取提交内容)
      这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。
    • Repeatable Read(可重读)
      这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。
    • Serializable(可串行化)
      这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
      这四种隔离级别采取不同的锁类型来实现,若读取的是同一个数据的话,就容易发生问题。例如:
      脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。
      不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。
      幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。

    死锁

    指两个以上的事务在统一资源上相互占用,并请求锁定对方的资源,从而导致恶循循环的现象


    上面都是一些理论知识,我们来看看一些实际的例子

    死锁

    事务1

    START TRANSACTION
    UPDATE USER SET name = '张三' WHERE id = 1;//A
    UPDATE USER SET name = '李四' WHERE id = 2;//B
    COMMIT;
    

    事务2

    START TRANSACTION
    UPDATE USER SET age = 100 WHERE id = 2;//C
    UPDATE USER SET age = 101 WHERE id = 1;//D
    COMMIT;
    

    我们看两个例子,正常来说这ABCD四个例子相互之间互不干扰,可是巧了,正好A和C同时执行完语句,同时也锁定住了这条数据,双方在准备执行下一条语句的时候发现B和D都被锁住了,于是等啊等,都需要对方等待释放锁,同时又持有对方所需要的锁,陷入了死循环,这就是死锁,目前市面上常用的InnoDB处理死锁的办法就是将最少行级的排他锁释放回滚,这也是相比较而言比较简单,大多数存储引擎所考虑的的算法

    隔离级别

    创建数据库

    CREATE TABLE test( id int unsigned AUTO_INCREMENT, name varchar(100) not null, age int(2) not null, primary key(id) )engine=innodb default charset=utf8;
    

    插入测试数据

    insert into test (age,name) values(12,'老王'),(20,'老李');
    
    数据截图

    --- --- --- --- --- --- --- --- -- --- --- --- --- --- --- --- --- --- 帅气的分割线--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

    read uncommitted(未提交读)

    1.首先我们设置当前的事物模式为read uncommitted(未提交读),这是test表的初始值


    用户A

    2.我们在创建B用户,针对其中一条数据进行事务修改,修改后查询修改数据;


    B用户

    3.我们此时在用a用户去查询数据库,我们发现a用户查询到的数据是b用户在事务中修改并且还未提交的数据,如果这时候b用户发生事务回滚,那么a用户就会出现脏读


    A用户

    Read Committed(读取提交内容)

    1.还是回到刚刚那个情景,设置当前模式为read committed,查询test表的所有记录;


    A用户

    2.在用户A提交事务之前,打开客户端B,更新表test;


    B用户

    3.这时候B还没有提交,我们看A用户查询的数据,发现他并没有查询到B用户所更改的数据,解决了脏读;


    A用户

    4.此时我们提交B用户的修改,B用户修改的已经提交到了数据库;


    B用户

    5.我们在用A用户读取数据,A此时还没有提交数据,我们再次读取数据时,发现数据不一致,这就是不可重复读;(务隔离级别为读提交时,写数据只会锁住相应的行)


    A用户

    Repeatable Read(可重读)

    1.用户A,设置事务模式为repeatable read模式,查询test记录;


    A用户

    2.用户B,开启新事务修改并提交;


    B用户

    3.用户A,查询出来的记录结果没变化,没有出现不可重复读问题;


    用户A

    4.接着A用户执行修改,本来应该是99+1等于100,但是结果为667,这是因为可重复读取是使用mvcc机制,select读取的是快照(历史版本),并且select不会更新版本号,而insert,update,delete会更新版本号,是当前读(当前版本)。

    用户A

    5.事务隔离级别为可重复读时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式是next-key 锁;如果检索条件没有索引,更新数据时会锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读。


    Serializable(可串行化)

    最后一种隔离,自己可以下去做一下尝试,这种隔离第一是开销最大,他是表锁,当A用户锁表的时候,b用户并不能进行相对应地操作,并发性极低,很少用到;


    参考资料

    相关文章

      网友评论

          本文标题:mysql(一):mysql的一些基础常识

          本文链接:https://www.haomeiwen.com/subject/gqokkqtx.html