Geek

博客园 首页 新随笔 联系 订阅 管理

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

  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 status\G

     

     

    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 写的好,一般不会有问题。

 

 

posted on 2020-04-08 13:42  .geek  阅读(863)  评论(0编辑  收藏  举报