select for update/lock in share mode 对事务并发性影响

事务并发性理解

事务并发性,粗略的理解就是单位时间内能够执行的事务数量,常见的单位是 TPS( transactions per second).

那在数据量和业务操作量一定的情况下,常见的提高事务并发性主要考虑的有哪几点呢?

1.提高服务器的处理能力,让事务的处理时间变短。

这样不仅加快了这个事务的执行时间,也降低了其他等待该事务执行的事务执行时间。

2.尽量将事务涉及到的 sql 操作语句控制在合理范围,换句话说就是不要让一个事务包含的操作太多或者太少。

在业务繁忙情况下,如果单个事务操作的表或者行数据太多,其他的事务可能都在等待该事务 commit或者 rollback,这样会导致整体上的 TPS 降低。但是,如果每个 sql 语句都是一个事务也是不太现实的。一来,有些业务本身需要多个sql语句来构成一个事务(比如汇款这种多个表的操作);二来,每个 sql 都需要commit,如果在 mysql 里 innodb_flush_log_at_trx_commit=1 的情况下,会导致 redo log 的刷新过于频繁,也不利于整体事务数量的提高(IO限制也是需要考虑的重要因素)。

3.在操作的时候,尽量控制锁的粒度,能用小的锁粒度就尽量用锁的粒度,用完锁资源后要记得立即释放,避免后面的事务等待。

但是有些情况下,由于业务需要,或者为了保证数据的一致性的时候,必须要增加锁的粒度,这个时候就是下面所说的几种情况。

select for update 理解

select col from t where where_clause for update 的目的是在执行这个 select 查询语句的时候,会将对应的索引访问条目进行上排他锁(X 锁),也就是说这个语句对应的锁就相当于update带来的效果。

那这种语法为什么会存在呢?肯定是有需要这种方式的存在啦!!请看下面的案例描述:

案例1:

前提条件:

mysql 隔离级别 repeatable-read ,

事务1:

建表:
CREATE TABLE `lockt` (
`id` int(11) NOT NULL,
`col1` int(11) DEFAULT NULL,
`col2` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `col1_ind` (`col1`),
KEY `col2_ind` (`col2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 插入数据 。。。。。 mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec) mysql> select * from lockt;
+----+------+------+
| id | col1 | col2 |
+----+------+------+
| 1 | 1 | 1 |
| 2 | 2 | 3 |
| 5 | 5 | 5 |
| 6 | 6 | 9 |
| 7 | 7 | 14 |
| 8 | 8 | 20 |
+----+------+------+
6 rows in set (0.00 sec)

然后另外一个事务2 进行了下面的操作:

mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> select * from lockt;
+----+------+------+
| id | col1 | col2 |
+----+------+------+
| 1 | 1 | 1 |
| 2 | 2 | 3 |
| 5 | 5 | 5 |
| 6 | 6 | 9 |
| 7 | 7 | 14 |
| 8 | 8 | 20 |
+----+------+------+
6 rows in set (0.00 sec) mysql> update lockt set col2= 144 where col2=14;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0 mysql> commit;
Query OK, 0 rows affected (0.00 sec)

结果:可以看到事务2 将col2=14 的列改为了 col2=144.

可是事务1继续执行的时候根本没有觉察到 lockt 发生了变化,请看 事务1 继续后面的操作:

mysql> select * from lockt;
+----+------+------+
| id | col1 | col2 |
+----+------+------+
| 1 | 1 | 1 |
| 2 | 2 | 3 |
| 5 | 5 | 5 |
| 6 | 6 | 9 |
| 7 | 7 | 14 |
| 8 | 8 | 20 |
+----+------+------+
6 rows in set (0.01 sec) mysql> update lockt set col2=col2*2 where col2=14;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0 Changed: 0 Warnings: 0 mysql> commit;
Query OK, 0 rows affected (0.00 sec) mysql> select * from lockt;
+----+------+------+
| id | col1 | col2 |
+----+------+------+
| 1 | 1 | 1 |
| 2 | 2 | 3 |
| 5 | 5 | 5 |
| 6 | 6 | 9 |
| 7 | 7 | 144 |
| 8 | 8 | 20 |
+----+------+------+
6 rows in set (0.00 sec)

结果: 事务1 明明查看到的存在 col2=12 的行数据,可是 update 后,竟然不仅没有改为他想要的col2=28 的值,反而变成了 col2=144 !!!!

这在有些业务情况下是不允许的,因为有些业务希望我通过 select * from lockt; 查询到的数据是此时数据库里面真正存储的最新数据,并且不允许其他的事务来修改只允许我来修改。(这个要求很霸气,但是我喜欢。。

这种情况就是很牛逼的情况了。具体的细节请参考下面的案例2:

案例2:

mysql 条件和案例1 一样。

事务1操作:

mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> select * from lockt where col2=20 for update;
+----+------+------+
| id | col1 | col2 |
+----+------+------+
| 8 | 8 | 20 |
+----+------+------+
1 row in set (0.00 sec)

事务2 操作:

mysql> select * from lockt;
+----+------+------+
| id | col1 | col2 |
+----+------+------+
| 1 | 1 | 1 |
| 2 | 2 | 3 |
| 5 | 5 | 5 |
| 6 | 6 | 9 |
| 7 | 7 | 144 |
| 8 | 8 | 20 |
+----+------+------+
6 rows in set (0.00 sec) mysql> update lockt set col2=222 where col2=20;

注意: 事务2 在执行 update lockt set col2=222 where col2=20; 的时候,会发现 sql 语句被 block住了,为什么会发现这种情况呢?

因为事务1 的 select * from lockt where col2=20 for update; 语句会将 col2=20 这个索引的入口给锁住了,(其实有些时候是范围的索引条目也被锁住了,暂时不讨论。),那么事务2虽然看到了所有的数据,但是想去修改 col2=20 的行数据的时候, 事务1 只能说 “不可能也不允许”。

后面只有事务1 commit或者rollback 以后,事务2 的才能够修改 col2=20 的这个行数据。

总结:

这就是 select for update 的使用场景,为了避免自己看到的数据并不是数据库存储的最新数据并且看到的数据只能由自己修改,需要用 for update 来限制。

select lock in share mode 理解

如果看了前面的 select *** for update ,就可以很好的理解 select lock in share mode ,in share mode 子句的作用就是将查找到的数据加上一个 share 锁,这个就是表示其他的事务只能对这些数据进行简单的select 操作,并不能够进行 DML 操作。

那它和 for update 在引用场景上究竟有什么实质上的区别呢?

lock in share mode 没有 for update 那么霸道,所以它有时候也会遇到问题,请看案例3

案例3:

mysql 环境和案例1 类似

事务1:

mysql> select * from lockt;
+----+------+------+
| id | col1 | col2 |
+----+------+------+
| 1 | 1 | 1 |
| 2 | 2 | 3 |
| 5 | 5 | 5 |
| 6 | 6 | 9 |
| 7 | 7 | 144 |
| 8 | 8 | 20 |
+----+------+------+
6 rows in set (0.00 sec) mysql> select * from lockt where col2=20 lock in share mode;
+----+------+------+
| id | col1 | col2 |
+----+------+------+
| 8 | 8 | 20 |
+----+------+------+
1 row in set (0.00 sec)

事务2 接着开始操作

mysql> select * from lockt;
+----+------+------+
| id | col1 | col2 |
+----+------+------+
| 1 | 1 | 1 |
| 2 | 2 | 3 |
| 5 | 5 | 5 |
| 6 | 6 | 9 |
| 7 | 7 | 144 |
| 8 | 8 | 20 |
+----+------+------+
6 rows in set (0.00 sec) mysql> select * from lockt where col2=20 lock in share mode;
+----+------+------+
| id | col1 | col2 |
+----+------+------+
| 8 | 8 | 20 |
+----+------+------+
1 row in set (0.01 sec)

后面的比较蛋疼的一幕出现了,当 事务1 想更新 col2=20 的时候,他发现 block 住了。

mysql> update lockt set col2=22 where col2=20;

解释:因为事务1 和事务2 都对该行上了一个 share 锁,事务1 以为就只有自己一个人上了 S 锁,所以当事务一想修改的时候发现没法修改,这种情况下,事务1 需要使用 for update 子句来进行约束了,而不是使用 for share 来使用。

可能用到的情景和对性能的影响

使用情景:

1. select *** for update 的使用场景

为了让自己查到的数据确保是最新数据,并且查到后的数据只允许自己来修改的时候,需要用到 for update 子句。

2. select *** lock in share mode 使用场景

为了确保自己查到的数据没有被其他的事务正在修改,也就是说确保查到的数据是最新的数据,并且不允许其他人来修改数据。但是自己不一定能够修改数据,因为有可能其他的事务也对这些数据 使用了 in share mode 的方式上了 S 锁。

性能影响:

select for update 语句,相当于一个 update 语句。在业务繁忙的情况下,如果事务没有及时的commit或者rollback 可能会造成其他事务长时间的等待,从而影响数据库的并发使用效率。

select lock in share mode 语句是一个给查找的数据上一个共享锁(S 锁)的功能,它允许其他的事务也对该数据上 S锁,但是不能够允许对该数据进行修改。如果不及时的commit 或者rollback 也可能会造成大量的事务等待。

for update 和 lock in share mode 的区别:前一个上的是排他锁(X 锁),一旦一个事务获取了这个锁,其他的事务是没法在这些数据上执行 for update ;后一个是共享锁,多个事务可以同时的对相同数据执行 lock in share mode。

(转载)Select for update/lock in share mode 对事务并发性影响的更多相关文章

  1. Select for update/lock in share mode 对事务并发性影响

    select for update/lock in share mode 对事务并发性影响 事务并发性理解 事务并发性,粗略的理解就是单位时间内能够执行的事务数量,常见的单位是 TPS( transa ...

  2. Mysql加锁过程详解(4)-select for update/lock in share mode 对事务并发性影响

    Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...

  3. SELECT ... LOCK IN SHARE MODE和SELECT ... FOR UPDATE locks在RR模式下可以看到最新的记录

    14.5.2.4 Locking Reads 锁定读: 如果你查询数据然后插入或者修改相关数据在相同的事务里, 常规的SELECT 语句不能给予足够的保护. 其他事务可以修改或者删除你刚查询相同的记录 ...

  4. SELECT LOCK IN SHARE MODE and FOR UPDATE

    Baronwrote nice article comparing locking hints in MySQL and SQL Server. In MySQL/Innodb LOCK IN SHA ...

  5. 深入理解SELECT ... LOCK IN SHARE MODE和SELECT ... FOR UPDATE

    概念和区别 SELECT ... LOCK IN SHARE MODE走的是IS锁(意向共享锁),即在符合条件的rows上都加了共享锁,这样的话,其他session可以读取这些记录,也可以继续添加IS ...

  6. mysql锁SELECT FOR UPDATE【转】

    MySQL 使用SELECT ... FOR UPDATE 做事务写入前的确认 以MySQL 的InnoDB 为例,预设的Tansaction isolation level 为REPEATABLE ...

  7. MySQL 使用SELECT ... FOR UPDATE 做事务写入前的确认(转)

    Select…For Update语句的语法与select语句相同,只是在select语句的后面加FOR UPDATE [NOWAIT]子句. 该语句用来锁定特定的行(如果有where子句,就是满足w ...

  8. mysql SELECT FOR UPDATE语句使用示例

    以MySQL 的InnoDB 为例,预设的Tansaction isolation level 为REPEATABLE READ,在SELECT 的读取锁定主要分为两种方式:SELECT ... LO ...

  9. 数据操纵:SELECT, INSERT, UPDATE, DELETE

    SELECT 句法 SELECT [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT] [SQL_CACHE ...

随机推荐

  1. JavaWeb——CSS总结

    CSS 记得大一下学期那会参加基地后就开始跟师兄师姐接触前端了,利用业余时间在站看各种视频.由于初次认知并且时间也能不固定集中,也存在跳跃式学习等等原因,这就导致了好多知识点要么漏掉要么没记全,只能懂 ...

  2. miniFTP项目实战二

    项目简介: 在Linux环境下用C语言开发的Vsftpd的简化版本,拥有部分Vsftpd功能和相同的FTP协议,系统的主要架构采用多进程模型,每当有一个新的客户连接到达,主进程就会派生出一个ftp服务 ...

  3. NOIP 模拟 $29\; \rm 最长不下降子序列$

    题解 \(by\;zj\varphi\) 观察这个序列,发现模数很小,所以它的循环节很小. 那么可以直接在循环节上做最长上升子序列,但是循环节中的逆序对会对拼接后的答案造成影响. 没有必要找逆序对个数 ...

  4. COM笔记-引用计数

    参考网站:https://www.cnblogs.com/fangyukuan/archive/2010/06/06/1752621.html com组件将维护一个称作是引用计数的数值.当客户从组件取 ...

  5. element ui loading加载开启与关闭

    参考:https://blog.csdn.net/qq_41877107/article/details/87690555 Vue项目引入element-ui,之后,将以下代码写入 mounted() ...

  6. java操作excel 工具类

    java操作excel 可参考https://blog.csdn.net/xunwei0303/article/details/53213130 直接上代码: 一.java生成excel文件: pac ...

  7. springmvc学习日志四

    一.回顾 1.文件上传 1.1引入fileupload的jar包 1.2在springmvc的配置文件中引入CommonsMutilpartResolver文件上传解析器 1.3在控制层在写入代码 2 ...

  8. 关于int和Integer缓存(一):以及设计构想(享元模式)

    关于Integer的值缓存:在介绍Integer的值缓存之前,我们需要了解的是,java中的包装类型,我们都知道java中有包装类型int                     Integer    ...

  9. 使用dom4j工具:读取xml(一)

    package dom4j_read; import java.io.File; import org.dom4j.Document; import org.dom4j.io.SAXReader; / ...

  10. docker容器 如何精简镜像减小体积

    写在前面 我们在上篇<Docker容器 关于镜像构建的安全问题>一起学习了如何构建一个基于安全的镜像,这篇小作文我们会学习镜像构建的另一个关键性问题,为何别人打造的镜像只有10MB而我的有 ...