mysql事务基础+基于innodb的行锁+间隙锁+如何锁定行

【0】README outlines are as follows :

  1. 行锁;
  2. 事务;
  3. 隔离级别;
  4. 行锁变表锁;
  5. 间隙锁;
  6. 如何锁定一行;
  7. 行锁总结;

【1】行锁+事务+存储引擎基础

1、行锁: 偏向于 innodb 存储引擎,开销大,加锁慢,会出现死锁; 锁定粒度最小,发送锁冲突的概率最低, 并发度最高;
2、innodb 与 myisam 的两点区别:

  • 区别1:innodb 支持事务; 
  • 区别2: innodb 采用了 行级锁;

补充0、事务定义: 

  • 事务就是一组原子性的sql查询,或者说一个独立的工作单元。即事务内的sql语句,要么全部执行成功,要么全部执行失败;

补充1:事务及其acid属性;事务的ACID概念:原子性automicity,一致性consistency,隔离性isolation,持久性durability;

  • 原子性:一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚;
  • 一致性;数据库总是从一个一致性状态转移到另一个一致性状态;
  • 隔离性:通常来说,一个事务所做的修改在最终提交前,对其他事务都是不可见的;
  • 持久性:一旦事务提交,则其所做的修改就会永久保存到数据库中;此时即使数据库崩溃,数据也不会丢失;

补充2:并发事务带来的问题:

  • 更新丢失, lost update; 最后的事务更新覆盖了其他事务所做的更新;
  • 脏读, dirty read;事务A读取到了事务B已修改但尚未提交的数据; 
  • 不可重复读, non-repeatable read;事务A读取到了事务B已经提交的数据,不符合隔离性;
  • 幻读, phantom read;事务A读取到了事务B提交的新增数据;

幻读和脏读的区别:

  • 脏读是事务A读取到了事务B里面修改了数据;
  • 幻读是事务A读取到了事务B里面新增了数据;

补充3:事务隔离级别; 脏读,不可重复读,幻读,其实都是数据一致性问题,必须由数据库提供一定的事务隔离机制来了解决;

mysql的4种隔离级别

  • 级别1)READ UNCOMMITED 未提交读:事务的修改,即使没有提交,对其他事务也是可见的;
  • 级别2)READ COMMITTED 提交读:一个事务从开始直到提交之前,所做的任何修改对其他事务不可见的;
  • 也叫不可重复读,因为两次执行相同的查询,可能得到不同的查询结果;
  • 级别3)REPEATABLE READ 可重复读:RR 解决了脏读问题。该级别保证在同一事务中多次读取同样记录的结果是一致的 ;(mysql的默认事务隔离级别) 但 RR 无法解决幻读问题,幻读指的是当某个事物在读取某个范围内的记录时,另外一个事务又在该范围内插入了一条新的记录,当之前的事务再次读取到该范围的记录时,会产生幻行; 不过 mysql中的 innodb 和 XtraDB 存储引擎通过多版本并发控制 MVVC(multiversion concurrency control) 解决了幻读问题;
  • 级别4)SERIALIZABLE 可串行化:最高隔离级别。通过强制事务串行执行,避免了前面说的幻读问题。简单说,SERIALIZABLE 会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁征用的问题;实际应用中很少考虑这种隔离级别;

补充说明:数据库的事务隔离级别越严格,并发副作用越小,但付出的代价也越大。因为事务隔离级别实质上就是使事务在一定程度上串行化进行,这显然与并发是矛盾的。 同时,不同的应用对读一致性和事务隔离程度的要求也是不同的。如许多应用对不可重复读和幻读不care, 但关心数据并发访问的能力;

查看当前数据库的事务隔离级别:  show variables like 'tx_isolation' ;

=======================================================================================

【2】行锁荔枝

2.0)造数

-- 造数据:
use mybatis;
-- 行锁荔枝
drop table if exists test_innodb_lock_tbl; 
create table test_innodb_lock_tbl (`rcrd_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '记录编号',`a` int NOT NULL default 0 COMMENT '列a',`b` varchar(20) NOT NULL default '' COMMENT '列b',PRIMARY KEY (`rcrd_id`)
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8 COMMENT='innodb行锁测试表';-- 插入数据 
-- 新建存储过程-调用函数批量插入数据 
drop procedure if exists insert_test_innodb_lock_tbl; 
delimiter ##
create procedure insert_test_innodb_lock_tbl(in start_num int, in max_num int) 
begin declare i int default 0;set autocommit=0;repeat set i=i+1;INSERT INTO mybatis.test_innodb_lock_tbl (a, b)VALUES(rand_num(), rand_str(10));until i = max_numend repeat;commit;
end ## 
delimiter ;call insert_test_innodb_lock_tbl(0, 10)
;-- 建立索引
alter table test_innodb_lock_tbl
add key `idx_a` (`a`) comment '索引a'
;
alter table test_innodb_lock_tbl
add key `idx_b` (`b`) comment '索引b'
;
-- 查看索引
show index from test_innodb_lock_tbl;
-- 查询数据
select * from test_innodb_lock_tbl;

2.1)行锁基本演示:

补充: 一旦会话1更新数据后且提交事务后, 会话2等待锁释放的线程结束阻塞状态,立即执行更新操作并更新成功; 

2.2)会话1操作具体步骤:

2.3)会话2操作具体步骤:

============================================================================

【补充荔枝】 会话1和会话2 各自更新不同的行,则两个会话间没有任何影响; 不存在说 会话1在没有提交事务前阻塞会话2的情况; 

【注意】索引失效行锁变表锁, 当索引使用不当时, 行锁会升级为表锁;
当varchar 类型 作为where子句的查询条件时, 如果没有写单引号,则行锁升级为表锁;
但是在mysql8中,如果没有写单引号,则sql 执行报错。

============================================================================

【3】间隙锁

1)什么是间隙锁? 
当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时, innodb 会给符合条件的已有数据记录的索引项加锁, 对于键值在条件范围内但并不存在的记录,叫做间隙-GAP
innodb 也会对这个间隙加锁,这种锁机制就是所谓的间隙锁;(next-key锁);

会话1:

会话2:

2)间隙锁的危害: 

  • 危害1)因为query执行过程中通过范围查找的话, 它会锁定整个范围内所有的索引键值,即使这个键值不存在; 
  • 危害2)间隙锁有一个比较致命的弱点,就是当锁定一个范围键值后,即使某些不存在的键值也会被无辜的锁定, 而造成在锁定的时候无法插入锁定键值范围内的任何数据。在某些场景下这可能会对性能造成很大危害;   

============================================================================

【4】如何锁定一行?

0)执行如下语句,就可以锁定行(在查询语句最后加上 for update 即可); 
select * from test_innodb_lock_tbl where a=101 for update;

1)会话1:

mysql> select * from test_innodb_lock_tbl order by a;
+---------+-----+------------+
| rcrd_id | a   | b          |
+---------+-----+------------+
|     107 | 101 | pkdOHXNXzD |
|     111 | 102 | 2000       |
|     103 | 103 | 181125     |
|     108 | 104 | 181125     |
|     106 | 105 | 181125     |
|     109 | 106 | IsNODBWgNx |
|     105 | 107 | xaMIfDzMnd |
|     102 | 108 | zhou222    |
|     104 | 109 | tZPdVseqrN |
|     110 | 109 | vkNjJSlDhd |
+---------+-----+------------+
10 rows in set (0.00 sec)mysql>
mysql>
mysql> begin;
Query OK, 0 rows affected (0.00 sec)mysql> select * from test_innodb_lock where a=8 fro update;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'fro update' at line 1
mysql>
mysql> select * from test_innodb_lock where a=101 for update;
ERROR 1146 (42S02): Table 'mybatis.test_innodb_lock' doesn't exist
mysql>
mysql> select * from test_innodb_lock_tbl where a=101 for update;
+---------+-----+------------+
| rcrd_id | a   | b          |
+---------+-----+------------+ 
|     107 | 101 | pkdOHXNXzD |
+---------+-----+------------+
1 row in set (0.00 sec)mysql> commit;
Query OK, 0 rows affected (0.00 sec)

2)会话2:

mysql> update test_innodb_lock_tbl set b='xxx' where a=101;
Query OK, 1 row affected (22.25 sec)
Rows matched: 1  Changed: 1  Warnings: 0

============================================================================

 

【5】行锁总结

1)innodb存储引擎:由于实现了行级锁定,虽然在锁机制的实现方面所带来的性能损耗高于表级锁, 但整体上的并发处理能力要远远高于 myisam的表级锁定;当系统并发量较高时,innodb的整体性能和myisam相比就会有比较明显的优势了;
2)但是, innodb的行级锁同样也有其脆弱的一面,当我们使用不当的时候,可能会让 innodb的整体性能表现不仅不能比 myisam高,甚至会更差;

3)如何分析行锁定 
3.1)通过检查 innodb_row_lock 状态变量来分析系统上的行锁的争夺情况;
show status like 'innodb_row_lock%'; 

状态说明如下:

  • Innodb_row_lock_current_waits:当前正在等待锁定的数量;
  • Innodb_row_lock_time:从系统启动到现在锁定总时间长度;(等待总时长-比较重要)
  • Innodb_row_lock_time_avg:每次等待锁花费的平均时间; (等待时长均值-比较重要)
  • Innodb_row_lock_time_max:从系统启动到现在等待最长的一次所花费的时间;
  • Innodb_row_lock_waits:系统启动后到现在总共等待的次数;(等待总次数-比较重要)

【注意】 等待次数很高,其每次等待时长不小的时候,我们就需要分析系统中为什么会有如此多的等待;然后根据分析结果着手指定优化计划(show profile);

4)优化建议:

  • 建议1)尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁;(如varchar类型在where子句中不加单引号‘’)
  • 建议2)合理设计索引,尽量缩小锁的范围;
  • 建议3)尽可能少的检索条件,避免间隙锁;
  • 建议4)尽量控制事务大小,减少锁定资源量和时间长度;
  • 建议5)尽可能低级别事务隔离;

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/330560.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

页面跳转、嵌套

页面跳转、嵌套 开发工具与关键技术:Visual Studio、MVC 作者:幻奏 撰写时间:2019.05.16在日常浏览网页的时候,我们常常能看到很多不同样式的网页,其中我们用的最多的应该就是跳转了,点击链接跳转、点击按…

Java高级进阶:自定义ClassLoader

转载自 Java高级进阶:自定义ClassLoader 假如我们的类不在classpath下,而我们又想读取一个自定义的目录下的class,如果做呢? 读取自定义目录的类 示例读取c:/test/com/test.jdk/Key.class这个类。 package com.test.jdk;public…

mysql如何分析sql执行效率和进行效率优化

【0】如何分析mysql中sql执行较慢的问题 步骤1、观察,至少跑一天,看看生产的慢sql情况;步骤2、开启慢查询日志,设置阈值,比如超过5秒钟就是慢sql, 并将它抓取出来;步骤3、explain慢sql分析&…

如何把模型表导入数据库

开发工具与关键技术:Power Designer、SQL 作者:幻奏 撰写时间:2019.05.23事先说明,我只是一个小萌新,我分享的文章是我在学习过程中学到的,不代表全是正确的,所以我要是有什么地方说错了&#x…

解决eclipse中tomcat无法识别maven web项目问题

eclipse工具中导入了maven web项目, 但是tomcat死活都识别不了, maven项目进行了clean install等操作, 但是仍无效, 后在网上搜索到以下答案, 解决问题 1. 右击项目 -> Debug As -> Maven build... 2. 在Goals中填入: -Dwtpversion2.0 eclipse:eclipse 对于WTP(Web Tool…

深入理解CAS算法原理

转载自 深入理解CAS算法原理1、什么是CAS?CAS:Compare and Swap,即比较再交换。jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronouse同步锁的一种乐观锁。JDK 5之前Java语言是靠synchronized关键字保证同…

如何写登录的记住账号

开发工具与关键技术:Visual Studio、MVC 作者:幻奏 撰写时间:2019.05.27上次我把如何登录的代码给写了,却没有写如何记住登录的账号密码,所以现在我就简单的写一下是如何记住账号密码的。 如果我们没写记住密码的话&am…

严重: Error configuring application listener of class org.springframework.web.context.ContextLoaderLis

博主 使用Eclipse 下的Mavn搭建的SSM框架的工程,出现以下错误 严重: Error configuring application listener of class org.springframework.web.context.ContextLoaderListener Java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoad…

java高级应用:线程池全面解析

转载自 java高级应用:线程池全面解析 什么是线程池? 很简单,简单看名字就知道是装有线程的池子,我们可以把要执行的多线程交给线程池来处理,和连接池的概念一样,通过维护一定数量的线程池来达到多个线程的复…

如何用for循环出数据库的数据

开发工具与关键技术:Visual Studio、MVC 作者:幻奏 撰写时间:2019.5.30在客房管理的系统中有很多不同的小格子,它们分别代表了不同的房间,可以动态的显示每间房间的状态,这个就是房态图。有很多系统应该都有…

Maven常见问题之【-Dmaven.multiModuleProjectDirctory system property is not set】

配置jdk时,声明vm参数,如下, 且需要保证 M2_HOME 环境变量已经配置了, 如下: C:\Users\pacoson>echo %M2_HOME% D:\software_cluster\apache-maven-3.3.9 -Dmaven.multiModuleProjectDirectory$M2_HOME

实现java多线程的3种方式,99%人没用过第3种

转载自 实现java多线程的3种方式,99%人没用过第3种 实现多线程的3种方式 1、继承Thread类 看jdk源码可以发现,Thread类其实是实现了Runnable接口的一个实例,继承Thread类后需要重写run方法并通过start方法启动线程。 继承Thread类耦合性太强了…

关于时间类型的问题

开发工具与关键技术:Visual Studio、MVC 作者:幻奏 撰写时间:2019.6.2我在做项目的时候遇到了一个问题,我要把时间显示到表格上,然后我像平常那样写,linq查询,然后返回数据,然后加载…

maven项目不编译xml文件

最近在搭建一个mavenspringMVCmybatis的项目&#xff0c;编译的时候mybatis生成的**Mapper.xml文件总是不编译&#xff08;classes文件夹内没有出现&#xff09;。 解决方法是在maven的pom.xml文件夹<build>标签下增加如下代码&#xff08;build标签的父标签是 project标…

多线程并发神器--ThreadLocal

转载自 多线程并发神器--ThreadLocal什么是ThreadLocal可以理解成线程本地变量&#xff0c;传统的线程对一个变量操作时操作的是同一个对象&#xff0c;也存在线程安全的问题。ThreadLocal是一个变量的本地副本&#xff0c;线程对变量的操作不会影响其他线程。首先看看ThreadLo…

如何获取复选框的值

开发工具与关键技术&#xff1a;Visual Studio、MVC 作者&#xff1a;幻奏 撰写时间&#xff1a;2019.6.7我们在很多地方都用到了复选框&#xff0c;数据表格里也有复选框&#xff0c;新增数据时也可能要复选框&#xff0c;修改时也要回填复选框&#xff0c;所以我们用到的地方…

使用log4j2打印mybatis的sql执行日志

【1】maven配置jar包依赖&#xff0c; 如下&#xff1a; <!-- 日志jar --><!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-…

Java多线程神器:join使用及原理

转载自 Java多线程神器&#xff1a;join使用及原理 join() join()是线程类 Thread的方法&#xff0c;官方的说明是&#xff1a; Waits for this thread to die. 等待这个线程结束&#xff0c;也就是说当前线程等待这个线程结束后再继续执行&#xff0c;下面来看这个示例就明白…

页面残留数据该如何处理

开发工具与关键技术&#xff1a;Visual Studio、MVC 作者&#xff1a;幻奏 撰写时间&#xff1a;2019.6.13关于页面数据残留的问题&#xff0c;我前几天就遇到了&#xff0c;刚开始的时候我写完那个页面是不知道它有毛病的&#xff0c;后来我才发现了它居然有一个小问题。 先来…

基于maven的SpringMVC+Spring+MyBatis+Log4j2的pom配置

【0】README&#xff1a;本文旨在给出可以正常跑 测试用例的项目依赖配置&#xff0c; 同时还会给出 maven 编译项目时的坑儿&#xff1b; 【1】 pom配置&#xff1a; <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/20…