MySQL与PostgreSQL的 SELECT FOR UPDATE

StringBoot-druid连接池-pgsql-超时取消-超时参数-canceling statement due to statement timeout 发表情况:个人网站csdn。可以理解是客户端主动取消,此时还没到数据库服务端statement_timeout的时间。实测相关的sql查询需要59秒,还是很耗时的。假如客户端的超时设置60秒,服务端statement_timeout是120秒,sql实际执行了70秒,那这个时候,会被客户端主动取消,。假如客户端的超时设置60秒,服务端statement_timeout是50秒,sql实际执行了65秒,那这个时候,sql实际执行超时时间超过了statement_timeout,。所以。 阅读详情



MySQL的行级锁

MySQL 版本:

1
2
3
4
5
6
7
8
9
mysql> select version();
+------------+
| version()  |
+------------+
| 5.6.17-log |
+------------+
1 row in set (0.00 sec)

mysql>

创建测试表

1
2
3
4
5
6
7
8
9
10
11
CREATE TABLE `shortlink` (
`id`  bigint(20) NOT NULL AUTO_INCREMENT ,
`long_url`  varchar(6000) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
`create_time`  timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ,
`update_time`  timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
ROW_FORMAT=COMPACT
;

插入测试数据

1
2
3
INSERT INTO `test`.`shortlink` (`id`, `long_url`, `create_time`, `update_time`) VALUES ('1', 'long1', '2015-12-21 15:03:41', '2015-12-21 15:03:41');
INSERT INTO `test`.`shortlink` (`id`, `long_url`, `create_time`, `update_time`) VALUES ('2', 'long2', '2015-12-21 15:30:56', '2015-12-21 15:30:56');
INSERT INTO `test`.`shortlink` (`id`, `long_url`, `create_time`, `update_time`) VALUES ('3', 'long3', '2015-12-21 15:35:48', '2015-12-21 15:35:48');

测试SELECT FOR UPDATE

where 没有索引 for update

session1:

1
2
3
4
5
6
7
8
9
10
11
12
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from shortlink where long_url = 'long2' for update;
+----+----------+---------------------+---------------------+
| id | long_url | create_time         | update_time         |
+----+----------+---------------------+---------------------+
|  2 | long2    | 2015-12-21 15:30:56 | 2015-12-24 17:25:27 |
+----+----------+---------------------+---------------------+
1 row in set (0.00 sec)

mysql>

这时开启另一个session2,更新id=2的数据

1
2
3
mysql> update shortlink set long_url = 'new long url' where id = 2;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>

发现它一直在等待.

又另一个session3,更新id=3的数据

1
2
3
mysql> update shortlink set long_url = 'new long url3' where id = 3;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>

发现它也是一直在等待

where 有索引 for update

session1:

1
2
3
4
5
6
7
8
9
10
11
12
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from shortlink where id = 2 for update;
+----+----------+---------------------+---------------------+
| id | long_url | create_time         | update_time         |
+----+----------+---------------------+---------------------+
|  2 | long2    | 2015-12-21 15:30:56 | 2015-12-24 17:25:27 |
+----+----------+---------------------+---------------------+
1 row in set (0.00 sec)

mysql>

这时开启另一个session2,更新id=2的数据

1
2
3
mysql> update shortlink set long_url = 'new long url' where id = 2;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>

这时开启另一个session3,更新id=3的数据(即非id=2的都可以)

1
2
3
4
5
mysql> update shortlink set long_url = 'new long url3' where id = 3;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql>

这时,发现,它可以立即更新.

MySQL for update 总结

  1. 只有 select for update 语句中使用了索引,才会是行级锁。否则就是全表锁.
  2. select for update 必须放在事务里才有效.

PostgreSQL 行级锁

PostgreSQL版本:

1
2
3
4
5
6
7
postgres=# select version();
                                                version
-------------------------------------------------------------------------------------------------------
 PostgreSQL 9.4.0 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3, 64-bit
(1 row)

postgres=#

创建测试表

1
2
3
postgres=# create table shortlink (id serial primary key, long_url varchar(6000) not null, create_time timestamp not null default CURRENT_TIMESTAMP, update_time timestamp not null default CURRENT_TIMESTAMP);
CREATE TABLE
postgres=#

注意,PG里的serial类型,并不会自动加索引的.

插入测试数据

1
2
3
4
5
6
7
postgres=# insert into shortlink (id, long_url, create_time, update_time) values (1, 'long1', '2015-12-21 15:03:41', '2015-12-21 15:03:41');
INSERT 0 1
postgres=# insert into shortlink (id, long_url, create_time, update_time) values (2, 'long2', '2015-12-21 15:30:56', '2015-12-21 15:30:56');
INSERT 0 1
postgres=# insert into shortlink (id, long_url, create_time, update_time) values (3, 'long3', '2015-12-21 15:35:48', '2015-12-21 15:35:48');
INSERT 0 1
postgres=#

测试 SELECT FOR UPDATE

where 没有索引 for update

session1

1
2
3
4
5
6
7
8
9
postgres=# begin ;
BEGIN
postgres=# select * from shortlink where long_url = 'long2' for update;
 id | long_url |     create_time     |     update_time
----+----------+---------------------+---------------------
  2 | long2    | 2015-12-21 15:30:56 | 2015-12-21 15:30:56
(1 row)

postgres=#

这时开启另一个session2,更新select for update里的某条数据.

1
2
3
4
5
6
postgres=# set lock_timeout = 5000;
SET
postgres=# update shortlink set long_url = 'long_url2' where id = 2;
ERROR:  canceling statement due to lock timeout
CONTEXT:  while updating tuple (0,2) in relation "shortlink"
postgres=#

注意,设置一下lock_timeout,默认是0,即无限等待.
这时,发现它是被锁住了.

又开启另一个session3,更新非select for udpate里的数据.

1
2
3
postgres=# update shortlink set long_url = 'long_url2' where id = 3;
UPDATE 1
postgres=#

可以发现,它是立即更新的.

where 有索引 for update

session1:

1
2
3
4
5
6
7
8
9
postgres=# begin ;
BEGIN
postgres=# select * from shortlink where id = 2 for update;
 id | long_url |     create_time     |     update_time
----+----------+---------------------+---------------------
  2 | long2    | 2015-12-21 15:30:56 | 2015-12-21 15:30:56
(1 row)

postgres=#

这时,开启另一个session去更新select for update中的某条数据:

1
2
3
4
postgres=# update shortlink set long_url = 'long_url222' where id = 2;
ERROR:  canceling statement due to lock timeout
CONTEXT:  while updating tuple (0,2) in relation "shortlink"
postgres=#

又开启另一个session3,去更新非select for update中的某条数据:

1
2
3
postgres=# update shortlink set long_url = 'long_url333' where id = 3;
UPDATE 1
postgres=#

发现它是可以立即更新的.

PostgreSQL for update 总结

根据测试,PostgreSQL的行级锁控制得更好点.无论where有没有触发到索引,都是行级锁.

总结

MySQL的select for update: 要有索引for update才是行级锁,否则就是全表锁.
PostgreSQL的selct for update: 只会锁select for update那部分的结果.

感觉PostgreSQL靠谱点.哈哈.

参考资料

  1. InnoDb locks set

  2. PostgreSQL runtime config client


转自:
http://emacsist.github.io/2015/12/24/MySQL%E4%B8%8EPostgreSQL%E7%9A%84-SELECT-FOR-UPDATE/
Statement cancelled due to timeout or client request 异常的修复【已解决】 Statement cancelled due to timeout or client request报错详情报错分析及解决问题重现及解决方案 报错详情 Caused by: com.mysql.jdbc.exceptions.MySQLTimeoutException: Statement cancelled due to timeout or client request at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2303) at 阅读详情

相关推荐

postgresql-jpa常见异常汇总

postgresql-jpa常见异常汇总

燕少江湖 2121

postgres 源码解析15 死锁检测机制-1

postgres死锁检测

Serendipity_Shy 2667

MySQL可重复读隔离级别原理与幻读问题解决方案

数据库事务隔离级别是保证数据一致性的关键技术,其中可重复读(RR)通过MVCC机制实现事务内读取一致性。MVCC利用版本链和undo日志维护数据多版本,确保同一事务内多次读取结果相同。然而标准RR隔离级别存在幻读问题,即其他事务插入新记录会导致查询结果集变化。MySQL通过间隙锁优化RR实现,结合锁定读(SELECT FOR UPDATE)解决写操作不一致。在实际工程中,需要根据业务场景选择隔离级别,报表类业务适合RR,高并发更新推荐READ COMMITTED+乐观锁。合理使用索引和事务拆分能有效提升RR

weixin_30702441的博客 288

Postgres 超时 (Timeout) 详解

即使同时设置了 statement_timeout 和 idle_in_transaction_session_timeout,如果事务是由短语句和中间的短暂停顿组成的,那么该事务仍然是开放的。与 idle_in_transaction_session_timeout 不同的是,idle_session_timeout 只适用于在事务中处于空闲状态的会话,而 idle_session_timeout 则适用于任何处于空闲状态的会话,无论它是否在事务中。在一个事务中终止任何超过指定时间的会话。

Bytebase的博客 4014

MySQL可重复读隔离级别下的幻读问题与解决方案

数据库事务隔离级别是保证数据一致性的关键技术,其中可重复读(Repeatable Read)隔离级别常被用于平衡性能与一致性需求。MVCC(多版本并发控制)机制通过维护数据行的版本号实现读一致性,而Next-Key Lock作为行锁与间隙锁的组合,能有效防止幻读现象。幻读指同一事务内两次相同查询看到不同结果集,特别是在高并发写入场景下容易发生。工程实践中,开发者需要理解FOR UPDATE等锁定读语句的使用场景,合理设计索引结构,在数据一致性与系统性能间取得平衡。本文深入解析MySQL InnoDB引擎如何

weixin_29296241的博客 307

SAP FB03凭证修改实战:巧用BAPI FI_DOCUMENT_CHANGE更新抬头与行项目

本文详细介绍了SAP FB03凭证修改的实战技巧,重点解析了BAPI FI_DOCUMENT_CHANGE的使用方法。通过该接口,用户可以在不冲销原凭证的情况下直接更新抬头文本(BKTXT)和行项目文本(SGTXT),确保凭证编号连续且符合审计要求。文章包含核心机制解析、完整实现步骤、错误处理方案以及高级应用场景,帮助开发者高效完成SAP财务凭证修改。

weixin_29251567的博客 426

mysql no wait,select for update [nowait | wait n] support Oracle,MySQL,PostgreSQL

起因在平时的的项目中,我们可能会用到对与数据进行悲观锁,比如select for update的语法,然后该语句默认会等待其他事务完成(提交/回滚/超时)时,才会返回结果,在实际业务场景中,这不是理想的做法,理论上应该在超过指定时间没有获取到锁,则应该返回其他业务处理,而不是一直等待。解决oracleoracle的语法中,支持直接在select for update语句后面跟上[nowait | ...

weixin_39819576的博客 1608

海康威视iSC平台视频流对接:RTSP、HLS、WS三种协议到底该怎么选?

本文深入分析海康威视iSC平台视频流对接中RTSP、HLS和WebSocket三种协议的优缺点,帮助开发者根据实时性、兼容性和网络环境做出最优选择。特别适合综合安防管理平台的Web视频监控系统开发,提升用户体验和系统性能。

weixin_28365523的博客 692

postgresql select for update 多行加锁顺序_超全面MySQL语句加锁分析(中篇)

REPEATABLE READ隔离级别下采用加锁的方式解决并发事务产生的问题时,REPEATABLE READ隔离级别与READ UNCOMMITTED和READ COMMITTED这两个隔离级别相比,最主要的就是要解决幻读问题,幻读问题的解决还得靠我们之前讲过的gap锁。对于使用主键进行等值查询的情况使用SELECT ... LOCK IN SHARE MODE来为记录加锁,比方说:SELECT...

weixin_39740737的博客 699

Oracle 常用语法汇总

CREATE TABLE 表名(COMMENT ON COLUMN 注释;-- 创建一个学生表STUDENT_ID NUMBER(10) PRIMARY KEY, -- 学生ID,主键FIRST_NAME VARCHAR2(50) NOT NULL, -- 学生名字,不允许为空LAST_NAME VARCHAR2(50) NOT NULL, -- 学生姓氏,不允许为空EMAIL VARCHAR2(100) UNIQUE, -- 学生电子邮箱,唯一。

拽着尾巴的鱼儿的博客 2159

【EMC电磁兼容】02.04——原理图的实战落地细节

原理图上的关于EMC的落地体现一、元器件的选型二、原理图上的EMC体现在哪里?1.芯片电源管脚滤波去耦:2.时钟电路滤波设计3.低速电路滤波抗干扰设计4.通讯接口电路的防护滤波5.系统输入电源端口电路的防护滤波6.系统接地的定义7.芯片软件功能的审查 一、元器件的选型 ​ 原理图最初设计涉及到选型元器件方面: 元器件选型 不仅仅功能需要满足要求,还需要考虑其它细节参数在不同应力下的反应,封装的不同也会产生不同的变化。 元器件替代 常常因为成本原因进行器件替代,除了要考虑功能参数相同时也要考虑系统参数

Time to Forget 2248

postgresql select for update 多行加锁顺序_PostgreSQL和Mysql的MVCC实现机制的差异对比

任何数据库的主要要求之一就是实现可伸缩性。只有将争用(锁定)最小化(如果不能一起删除),才可以实现。由于读/写/更新/删除是数据库中发生的一些主要的频繁操作,因此对于这些操作并发进行而不被阻塞非常重要。为了实现这一目标,大多数主要数据库都采用了一种称为多版本并发控制的并发模型,该模型将争用降低到最低限度。什么是MVCC多版本并发控制(以下简称MVCC)是一种算法,可通过维护同一对象的多个版本来提供...

weixin_39560029的博客 449

Habitat-baselines v0.1.7防踩坑手把手带你跑通(全网唯一)

Habitat-baselines v0.1.7防踩坑手把手带你跑通(全网唯一)

shannanshouyin的博客 1278

【任务调度:数据库锁 + 线程池实战】1、多节点抢任务?SELECT FOR UPDATE SKIP LOCKED 才是真正的无锁调度神器

是分布式任务调度领域的一颗明珠,它以极简的方式解决了多节点竞争下的锁等待、死锁和性能问题。分布式调度的核心痛点的原理与语法各主流数据库的支持情况与差异如何设计任务表及优化索引在 Spring Boot 中集成的完整示例当然,没有银弹。也有其适用范围和限制(如 MySQL 的索引要求、事务长度的控制等)。但在大多数场景下,它比传统方案更简单、更高效。下一篇文章,我们将深入比较PostgreSQL 与 MySQL 在 SKIP LOCKED 上的实现差异。

2025博客之星Top81。专注AI工程化与架构实战。从分布式思维到模型部署,用工程化视角为你厘清AI落地的真实路径。 989

手把手教你用Apple Developer App完成苹果开发者账号注册(含证件验证失败解决方案)

本文详细指导如何通过Apple Developer App完成苹果开发者账号注册,特别针对证件验证失败问题提供解决方案。从准备工作到注册流程,再到验证失败的处理方法,帮助开发者顺利完成注册,避免常见错误。

moss5的博客 1161

ESP32对接百度智能云语音识别:从硬件配置到API调用的完整指南

本文详细介绍了ESP32对接百度智能云语音识别的完整流程,从硬件配置到API调用,涵盖麦克风选择、音频处理、错误处理及性能优化等关键环节。通过实战案例展示如何实现低成本、高效率的语音交互方案,特别适合智能硬件开发者参考。

weixin_29198045的博客 375

mysql事务性postgre_PostgreSQL与MySQL事务隔离级别的不同

数据库的事务隔离级别有4种:READ UNCOMMITTEDREAD COMMITTEDREPEATABLE READSERIALIZABLE而在PostgreSQL事务隔离级别中,READ UNCOMMITTED是之间被认为是READ COMMITTED,所以实际上只有三种。PostgreSQL默认隔离级别是READ COMMTIED,而MySQL默认为REPEATABLE READ,另MySQ...

weixin_29538497的博客 443

车辆网络安全ISO/SAE 21434解读(一)概述

ISO/SAE 21434 《道路车辆 网络安全工程》是SAE和ISO共同制定的一项针对道路车辆的网络安全标准,它是一个面向汽车行业全供应链(OEM及各级供应商)的车辆网络安全管理指导文件

xiaoxiabang的博客 8427

Django悲观锁怎么用_select_for_update()在事务中锁定行记录

什么时候必须用 select_for_update() 而不是普通查询当多个并发请求可能同时读取同一行、再基于该行数据做修改(比如扣库存、生成唯一订单号、递增计数器),且你要求「读到的值在后续更新时仍有效」,就必须上悲观锁。但如果 filter() 条件没走索引,可能升级为表锁(MySQL 尤其危险)select_for_update() 的参数怎么选:nowait、skip_locked、of默认行为是阻塞等待锁释放,但线上服务通常不能卡住请求。

2401_87169652的博客 183

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

如何实现SQL特定业务逻辑钩子_利用触发器扩展功能点

真正能做的:只读查询(SELECT ... INTO 变量)、简单计算、INSERT/UPDATE/DELETE 其他表、调用无副作用函数如果必须加锁或跨表强一致性校验,得把逻辑提到应用层,或改用存储过程封装整个操作MySQL 8.0+ 支持在触发器中调用 GET_LOCK() 做轻量级互斥,但要注意锁生命周期和超时,别忘了 RELEASE_LOCK()PostgreSQL 的 AFTER ROW 触发器拿不到新旧行完整状态?提前解构BEFORE 触发器可修改 NEW,AFTER 不行;

180

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

如何防止SQL表主键重复_通过触发器实现逻辑ID分配

主键重复时触发器根本拦不住 INSERT 报错触发器无法阻止主键冲突报错,因为 PRIMARY KEY 约束在触发器执行前就已校验。实操建议:主键仍用 INT AUTO_INCREMENT,另加一个 VARCHAR 字段存逻辑ID(如 order_no)触发器只写 NEW.order_no := CONCAT('ORD', DATE_FORMAT(NOW(), '%Y%m%d'), LPAD(@next_seq := @next_seq + 1, 4, '0'));

DaqunChen的博客 202

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

深入解析select for update:锁机制与高并发优化实践

数据库锁机制是保证数据一致性的核心技术,其中排他锁(X锁)通过阻塞并发修改确保事务隔离。select for update作为显式加锁语法,在MySQL等关系型数据库中广泛用于解决并发更新问题,但其不当使用会导致连接池耗尽、系统卡顿等严重性能问题。本文从InnoDB引擎的锁升级路径、不同隔离级别下的锁行为差异等原理出发,结合电商库存扣减等典型应用场景,深入分析锁等待超时、死锁预防等工程实践要点,并给出乐观锁、分布式锁等高并发替代方案。针对开发者常见的全表锁定、长事务持锁等五大陷阱,提供可落地的索引优化和连接

weixin_29198045的博客 312

如何预防SQL大数据量更新导致的内存溢出_分段处理与流式插入

别依赖“单条 SQL 更快”——它可能更快地压垮内存确认你的驱动是否自动缓存结果:MySQL Connector/J 默认 useCursorFetch=true 才能流式读,否则 ResultSet 会预加载全部UPDATE 本身不返回结果集,但如果你用 SELECT ... FOR UPDATE + 循环更新,就极易触发客户端 OOMMySQL 分段 UPDATE 怎么写才不锁表太久直接 WHERE id BETWEEN?是最稳妥的分段方式,前提是 id 是主键或有高效索引。

2401_88772450的博客 209

聊一聊数据库中的锁

例如:- 事务A锁住行1,等待行2- 事务B锁住行2,等待行1解决办法是:按照固定的顺序获取锁,或者使用超时机制。锁的粒度可以从行级别到表级别,甚至到数据库级别。## 锁的实战演示:MySQL中的行锁MySQL的InnoDB引擎支持行级锁,这是最常用的锁类型之一。线程1将库存减为7,线程2将库存减为8,但最终结果取决于线程执行顺序,可能为7或8,而不是预期的5(10-3-2)。### 示例1:模拟并发更新导致的数据竞争在这个示例中,我们将模拟两个并发事务同时更新同一行数据,没有使用锁时会导致数据不一致。

laewDUSi3的博客 213

如何防止SQL触发器导致事务超时_拆分逻辑为异步队列处理

触发器中禁止出现任何网络 I/O(如 curl、http_request)、文件写入、跨库查询避免在触发器中调用存储过程,除非该过程已明确验证为纯内存计算、无锁、毫秒级完成MySQL 8.0+ 的 VALIDATE PASSWORD 类插件函数也需警惕——某些配置下会隐式触发磁盘读用「插入消息表 + 定时轮询」替代同步触发逻辑最轻量、兼容性最强的解法:把原本想在触发器里干的事,改成往一张专用消息表里插一条记录,再由外部进程异步消费。不改应用代码,不依赖消息中间件,MySQL 原生支持。

2403_88326109的博客 195

解决分布式定时任务痛点:db-scheduler如何避免重复执行与数据一致性

在分布式系统中,定时任务的调度与执行面临诸多挑战,如任务重复执行、数据不一致等问题。db-scheduler作为一款Persistent cluster-friendly scheduler for Java,专为解决这些痛点而生。它通过数据库锁机制和事务管理,确保在集群环境下任务的可靠执行,同时保障数据的一致性。 ## 分布式定时任务的核心挑战 分布式环境下的定时任务调度主要面临两大难题:*

gitblog_00998的博客 443
上一篇: 使用Maven构建多模块项目
下一篇: Maven工程产生Jar时Main-Class和Class-Path的配置文件
zljjava
博客等级 码龄15年 155粉丝 15原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值