摘要:最近做一个接诊需求遇到一个问题,假设一个订单咨询超过3次就不能再接诊,但如果两个医生同时对该订单进行咨询,查数据库的时候查到的接诊次数都是2次,那两个医生都能接诊,所谓接诊可以理解为更新了接诊次数,此时就出现了问题(接诊了4次)。

其实这个问题看似很明朗,但想要完全解决需要理解事务和锁的概念,以前总对事务的隔离级别有点云里雾里,现在可以通过这个案例可以理清楚。

事务

操作数据库最小的工作单位,简单讲就是将多条dml(增删改)语句联合完成。要么同时成功,要么同时失败。看到这里你可能会发现光加事务解决不了上述问题,而且加了事务之后,多条事务之间的相互关系就涉及到事务的隔离级别,所以接着往下看。

事务隔离级别

READ UNCOMMITTED(读未提交,脏读)

事务中的修改,即使没有提交,对其他会话也是可见的。可以读取未提交的数据——脏读。脏读会导致很多问题,一般不适用这个隔离级别.。

  1. -- ------------------------- read-uncommitted实例 ------------------------------
  2. -- 设置全局系统隔离级别
  3. SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
  4. -- Session A
  5. START TRANSACTION;
  6. SELECT * FROM USER;
  7. UPDATE USER SET NAME="READ UNCOMMITTED";
  8. -- commit;
  9.  
  10. -- Session B
  11. SELECT * FROM USER;
  12.  
  13. //SessionB Console 可以看到Session A未提交的事物处理,在另一个Session 中也看到了,这就是所谓的脏读
  14. id name
  15. 2 READ UNCOMMITTED
  16. 34 READ UNCOMMITTED

READ COMMITTED(读已提交,不可重复读) 

一般数据库都默认使用这个隔离级别(MySQL 不是), 这个隔离级别保证了一个事务如果没有完全成功(commit 执行完),事务中的操作对其他会话是不可见的。

  1. -- ------------------------- read-cmmitted实例 ------------------------------
  2. -- 设置全局系统隔离级别
  3. SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
  4. -- Session A
  5. START TRANSACTION;
  6. SELECT * FROM USER;
  7. UPDATE USER SET NAME="READ COMMITTED";
  8. -- COMMIT;
  9.  
  10. -- Session B
  11. SELECT * FROM USER;
  12.  
  13. //Console OUTPUT:
  14. id name
  15. 2 READ UNCOMMITTED
  16. 34 READ UNCOMMITTED
  17.  
  18. ---------------------------------------------------
  19. -- Session A执行了commitSession B得到如下结果:
  20. id name
  21. 2 READ COMMITTED
  22. 34 READ COMMITTED

REPEATABLE READ (可重复读)

一个事务中多次执行统一读 SQL,返回结果一样。这个隔离级别解决了脏读的问题,幻读问题。这里指的是 innodb 的 rr 级别,innodb 中使用 next-key 锁对"当前读"进行加锁,锁住行以及可能产生幻读的插入位置,阻止新的数据插入产生幻行。

会话T1事务中执行一次查询,然后会话T2新插入一行记录,这行记录恰好可以满足T1所使用的查询的条件。然后T1又使用相同 的查询再次对表进行检索,但是此时却看到了事务T2刚才插入的新行。这个新行就称为“幻像”,因为对T1来说这一行就像突然 出现的一样。innoDB 的 RR 级别无法做到完全避免幻读。

SERIALIZABLE (可串行化)

最强的隔离级别,通过给事务中每次读取的行加锁,写加写锁,保证不产生幻读问题,但是会导致大量超时以及锁争用问题。

mysql默认的隔离级别是可重复读,看到这里大家应该明白,即使隔离级别是可重复读,但因为select操作时并未加锁,导致都会查到符合条件的数据,所以这里要引入一个锁的概念:行级锁。

行级锁

  • 共享锁(S) 共享锁也称为读锁,读锁允许多个连接可以同一时刻并发的读取同一资源,互不干扰;

  • 排他锁(X) 排他锁也称为写锁,一个写锁会阻塞其他的写锁或读锁,保证同一时刻只有一个连接可以写入数据,同时防止其他用户对这个数据的读写。

总结(解决方案)

其实上文分析了那么多,最后的解决方案很简单。就是在原来的read和update合起来加事务,原来的select语句加排他锁,即在select语句后面加for update。假如有事务A,B,加入排他锁之后,假设事务A先获得锁,事务B必须等到事务A commit之后才能开始select,所以读到的是最新修改的数据。至于为什么不加共享锁,除了可能造成脏写之后,在这种情况下还可能造成死锁。假如两个事务 A 、 B 都读取同一行记录,那么在这一行就加上了共享锁,但是 A 和B 事务中都需要修改这一行,那么都要等待对方释放共享锁才能进行,结果造成了死锁。

mysql:如何解决数据修改冲突(事务+行级锁的实际运用)的更多相关文章

  1. Mysql在InnoDB引擎下索引失效行级锁变表锁案例

    先做好准备,创建InnoDB引擎数据表,并添加了相应的索引 DROP TABLE IF EXISTS `innodb_lock`; CREATE TABLE `innodb_lock` ( `a` ) ...

  2. Mysql的行级锁

    我们首先需要知道的一个大前提是:mysql的锁是由具体的存储引擎实现的.所以像Mysql的默认引擎MyISAM和第三方插件引擎 InnoDB的锁实现机制是有区别的. Mysql有三种级别的锁定:表级锁 ...

  3. SQL Server 中 ROWLOCK 行级锁

    一.ROWLOCK的使用 1.ROWLOCK行级锁确保,在用户取得被更新的行,到该行进行更新,这段时间内不被其它用户所修改.因而行级锁即可保证数据的一致性,又能提高数据操作的并发性. 2.ROWLOC ...

  4. Mysql事务及行级锁的理解

    在最近的开发中,碰到一个需求签到,每个用户每天只能签到一次,那么怎么去判断某个用户当天是否签到呢?因为当属表设计的时候,每个用户签到一次,即向表中插入一条记录,根据记录的数量和时间来判断用户当天是否签 ...

  5. Mysql事务及行级锁

    事务隔离级别 数据库事务隔离级别,只是针对一个事务能不能读取其它事务的中间结果. Read Uncommitted (读取未提交内容) 在该隔离级别,所有事务都可以看到其他未提交事务的执行结果.本隔离 ...

  6. Mysql的事务及行级锁

    转自:http://www.cnblogs.com/edwinchen/p/4171866.html 以签到为例,每个用户每天只能签到一次,那么怎么去判断某个用户当天是否签到呢?因为当初表设计的时候, ...

  7. [数据库事务与锁]详解五: MySQL中的行级锁,表级锁,页级锁

    注明: 本文转载自http://www.hollischuang.com/archives/914 在计算机科学中,锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的 ...

  8. MySQL行级锁,表级锁,页级锁详解

    页级:引擎 BDB. 表级:引擎 MyISAM , 理解为锁住整个表,可以同时读,写不行 行级:引擎 INNODB , 单独的一行记录加锁 表级,直接锁定整张表,在你锁定期间,其它进程无法对该表进行写 ...

  9. MySQL行级锁、表级锁、页级锁详细介绍

    原文链接:http://www.jb51.net/article/50047.htm 页级:引擎 BDB.表级:引擎 MyISAM , 理解为锁住整个表,可以同时读,写不行行级:引擎 INNODB , ...

随机推荐

  1. Eureka 集群Demo

    由于自己遇到了一些eureka集群疑问,就自己搭了一个集群demo进行测试.测试中通过两个eureka相互注册形成集群,两个服务提供者向eureka中注册服务,两个服务消费者通过feign进行服务调用 ...

  2. Java CPU占用过高之诊断

    Redhat, java 先用top 命令(默认为cpu占用排序), 确认java占用CPU kill -3 <java pid> ps Hh -eo pid,tid,pcpu | sor ...

  3. burpsuite无法拦截本地流量

    参考文章链接:https://blog.csdn.net/tb_youth/article/details/103436796?utm_medium=distribute.pc_relevant.no ...

  4. 读取xlsx文件的内容输入到xls文件中

    package com.cn.peitest.excel; import java.io.File; import java.io.FileInputStream; import java.io.Fi ...

  5. easyui字典js 切换 jsp页面显示的内容

    在列表中直接切换 formatter: function (value) {var name;if(value==0){name='待审批'}else if(value==1){name='通过'}e ...

  6. 2020DevOps状态报告

    这是Puppet报告的走过的第九个年头,本次报告基于对2400名IT.开发.信息安全行业的技术人员的调研,着重勾画了DevOps状态的两大趋势:平台模型.需求变更的管理.多年来,我们已经证明了DevO ...

  7. webapplicationContext之ServletContext等相关概念说明

    1)ServletContext是一个全局的储存信息的空间,所有用户共用一个,其信息必须是线程安全且共享的. ServletContext有一个接口定义:ServletContext接口.此接口定义了 ...

  8. javascript 匿名函数的理解(转)

    原网址 http://www.jb51.net/article/21948.htm javascript 匿名函数的理解(透彻版) 代码如下: (function(){ //这里忽略jQuery所有实 ...

  9. 一次mongo查询不存在字段引发的事故

    话说今天的一个小小的查询失误给了我比较深刻的教训,也让我对mongo有了更深刻的理解,下面我们来说说这个事情的原委: 我们经常使用阿里云子账号在DMS上查询线上数据库数据,今天也是平常的一次操作 集合 ...

  10. Alpha冲刺--总结随笔

    一.项目预期计划 时间 (天) 前端预期计划 完成情况 后端预期计划 完成情况 1-2 前端开始基本页面的设计 完成 整合项目依赖,搭建基本框架,建立数据库 完成 3-5 前端基础页面的实现与完善 完 ...