• 数据库并发的问题


    并发操作会带来一系列的问题

    1. 更新丢失(lost update)

      当两个或多个事务选择了同一行然后基于最初选定的值更新改行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新的问题,最后更新覆盖了由其他事务所做的更新

    2. 脏读 (Dirty reads)

      一个事务正在对一条记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致的状态;这时,另一个事务也读取同一条基础,如果不加控制,第二个事务读取这些"脏"数据,并据此作进一步的处理,就会产生未提交的数据的依赖关系,这种叫做"脏读"

    3. 不可重复读(Non-Repeatable reads)

      一个事务在读取某些数据的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生改变,或者某些记录被删除了!! 这就叫不可重复读

      (不符合隔离性)

    4. 幻读

      一个事务按相同的查询条件读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象叫做"幻读",好像重来没出现过

       

      设置了 mysql 事务隔离级别, mysql对于操作同一行数据会自动加锁

       

       

      对于可重复读, mysql使用的是 MVCC 机制 ,multi version concurrent control,多版本并发控制机制

      select 操作不会更新版本,每次查询都会做一次快照,用的是快照版本。然后修改后,真实数据以及和快照版本不一致了,但是 mysql为了让逻辑准确,更新的时候会那数据库最新的数据进行更新,而读是读的快照版本的数据。

      商品超卖,就是这种原因。

       

      https://blog.csdn.net/huaishu/article/details/89924250

      这种就是当前读和快照读的区别

      快照读会让性能高一点。所以 select 出来再 update 会有 bug

      注意点:sql应该这样写: update account set balance = balance-50 where id = 1;

       

       

       

       

      可重复读的话,select不会更新版本好,是快照读(历史版本),而insert 、update和delete 会更新版本好,是当前读(当前版本)

      所以更新之后再开查就可能会有幻读的现象:

       

      session1: select * from account;

      session2: insert into account (name,money) values('ss',100);

      session1: update account set name = 'lyr' where id = 1 ;

      session1: select * from account;

       

      如果 session1: 没有update account 这张表,会用快照读,不会出现幻读的问题

      然而: session1: update 了 account这张表,那么就会从快照读改当前读

      而session2 这个时候 插入了一条 name='ss', money=100 的数据

      session1 再来查表,发现无缘无故有多了一条,这个就像幻觉一样的数据(幽灵般的出现了)

      这个就是幻读

       

      改成 串行化,那就什么问题也没有了,但是不应该这样,因为效率低

      mysql 使用可重复读 兼顾了效率尽量的解决了脏读和不可重复读的问题

       

       

      查看mysql近期死锁的日志信息:

      show engine innodb statusG

       

       

      mysql的优化:

      1. 尽可能让所有数据检索通过索引完成,避免无索引行锁升级为表锁
      2. 合理设计索引,尽量缩小锁的范围
      3. 尽可能检索检索条件,避免间隙锁
      4. 尽量控制事务大小,减少锁定资源量和时间长度
      5. 尽可能低级别的事务隔离

    这样就可以解决并发问题了

    1. update account set money = money-1 where id='llyr' and money >0;

     

    mysql可以使用一个间隙锁,只要是范围的话 mysql自动加锁,一般不会有幻读问题

     

    条件 是一个范围,mysql就加锁了

    这样可以解决幻读问题

    https://blog.csdn.net/spring_model/article/details/53992450

    还有其他的锁,比如 for update 独占锁之类的

     

    mysql 开启事务的时候 update语句的时候加锁,COMMIT后释放

    所以sql 写的好,一般不会有问题。

     

     

  • 相关阅读:
    Hibernate 项目查询数据报 UnknownEntityTypeException
    C# 实现保留两位小数的方法
    在vs中安装和引用科学计算库 Math.NET Numerics
    C# 特性(Attribute)
    Modbus测试工具ModbusPoll与Modbus Slave使用方法
    StarUML3.0学习笔记
    转载:接近开关NPN型与PNP型的相互代替
    C#中(int)、int.Parse()、int.TryParse()和Convert.ToInt32()的区别
    DateTime.ToString() Patterns
    _056_根据年份判断十二生肖
  • 原文地址:https://www.cnblogs.com/lyr-2000/p/12659437.html
Copyright © 2020-2023  润新知