Postgresql源码(124)两个事务更新同一行数据时的行为和原理分析

XactLockTableWait函数、transactionid锁的一些原理和分析

结论

  • 更新行时,会根据xmax拿transactionid锁,等对应的事务结束。
    • 如果结束是回滚,则heap_update继续更新。
    • 如果结束时提交,则heap_update要返回上层ExecUpdate调用EvalPlanQual重新拿到数据再更新(也有可能更新后不符合谓词就看不到了)。

场景

先执行事务1更新3为30,不提交。

再执行事务2更新所有小于10的数。

drop table t81;
create table t81(i int);
insert into t81 select t.i from generate_series(1,5) t(i);-- 事务745
begin;
update t81 set i = 30 where i = 3;-- 事务746
begin;
update t81 set i = 100 where i < 10;

事务二的update会卡住等待事务1。

postgres=# select * from pg_locks where pid <> pg_backend_pid() order by pid,locktype;locktype    | database | relation | page | tuple | virtualxid | transactionid | classid | objid | objsubid | virtualtransaction |  pid  |       mode       | granted | fastpath |waitstart
---------------+----------+----------+------+-------+------------+---------------+---------+-------+----------+--------------------+-------+------------------+---------+----------+-------------------------------relation      |        5 |    16389 |      |       |            |               |         |       |          | 3/446              | 29044 | RowExclusiveLock | t       | t        |transactionid |          |          |      |       |            |           745 |         |       |          | 3/446              | 29044 | ExclusiveLock    | t       | f        |virtualxid    |          |          |      |       | 3/446      |               |         |       |          | 3/446              | 29044 | ExclusiveLock    | t       | t        |relation      |        5 |    16389 |      |       |            |               |         |       |          | 4/22               | 29246 | RowExclusiveLock | t       | t        |transactionid |          |          |      |       |            |           746 |         |       |          | 4/22               | 29246 | ExclusiveLock    | t       | f        |transactionid |          |          |      |       |            |           745 |         |       |          | 4/22               | 29246 | ShareLock        | f       | f        | xxxx-xx-xx 16:53:14.828479+08tuple         |        5 |    16389 |    0 |     3 |            |               |         |       |          | 4/22               | 29246 | ExclusiveLock    | t       | f        |virtualxid    |          |          |      |       | 4/22       |               |         |       |          | 4/22               | 29246 | ExclusiveLock    | t       | t        |
(8 rows)

分析

事务746的等锁堆栈

...#5  0x00000000009a4c23 in WaitOnLock (locallock=0x1f8d120, owner=0x1f9dbc0) at lock.c:1818
#6  0x00000000009a3961 in LockAcquireExtended (locktag=0x7ffd197ae4f0, lockmode=5, sessionLock=false, dontWait=false, reportMemoryError=true, locallockp=0x0) at lock.c:1082
#7  0x00000000009a2f3f in LockAcquire (locktag=0x7ffd197ae4f0, lockmode=5, sessionLock=false, dontWait=false) at lock.c:740
#8  0x00000000009a181c in XactLockTableWait (xid=740, rel=0x7f29222b20d8, ctid=0x7ffd197ae594, oper=XLTW_Update) at lmgr.c:702
#9  0x00000000004f1453 in heap_update (relation=0x7f29222b20d8, otid=0x7ffd197ae8aa, newtup=0x205baf8, cid=0, crosscheck=0x0, wait=true, tmfd=0x7ffd197ae8d8, lockmode=0x7ffd197ae82c, update_indexes=0x7ffd197ae828) at heapam.c:3316
#10 0x00000000004fdfa3 in heapam_tuple_update (relation=0x7f29222b20d8, otid=0x7ffd197ae8aa, slot=0x205b518, cid=0, snapshot=0x1f98370, crosscheck=0x0, wait=true, tmfd=0x7ffd197ae8d8, lockmode=0x7ffd197ae82c, update_indexes=0x7ffd197ae828) at heapam_handler.c:327
#11 0x000000000077f5a0 in table_tuple_update (rel=0x7f29222b20d8, otid=0x7ffd197ae8aa, slot=0x205b518, cid=0, snapshot=0x1f98370, crosscheck=0x0, wait=true, tmfd=0x7ffd197ae8d8, lockmode=0x7ffd197ae82c, update_indexes=0x7ffd197ae828) at ../../../src/include/access/tableam.h:1535
#12 0x000000000078278f in ExecUpdateAct (context=0x7ffd197ae8b0, resultRelInfo=0x205a4a8, tupleid=0x7ffd197ae8aa, oldtuple=0x0, slot=0x205b518, canSetTag=true, updateCxt=0x7ffd197ae824) at nodeModifyTable.c:2101
#13 0x0000000000782cbb in ExecUpdate (context=0x7ffd197ae8b0, resultRelInfo=0x205a4a8, tupleid=0x7ffd197ae8aa, oldtuple=0x0, slot=0x205b518, canSetTag=true) at nodeModifyTable.c:2322
#14 0x000000000078533d in ExecModifyTable (pstate=0x205a298) at nodeModifyTable.c:3824
#15 0x0000000000746fa6 in ExecProcNodeFirst (node=0x205a298) at execProcnode.c:464
#16 0x000000000073ad27 in ExecProcNode (node=0x205a298) at ../../../src/include/executor/executor.h:273...

可以看到事务746在等待事务745的transactionid锁。

事务746流程分析

heap_update拿到目标元组的otid和拼好的新元组后

heap_update(Relation relation, ItemPointer otid, HeapTuple newtup, ...)

先把buffer锁上,因为另一个事务已经更新完了,所以buffer锁当前可以拿到。

LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);

然后拿到被修改元组的xmax,万一被别人改了呢?例如这里xwait=745,且745还没提交。

xwait = HeapTupleHeaderGetRawXmax(oldtup.t_data);

注意这里要先放buffer,因为有可能别的事务会修改,后面需要重新锁上拿数据

LockBuffer(buffer, BUFFER_LOCK_UNLOCK);

先把行锁拿到,避免别人正在更新

heap_acquire_tuplock(relation, &(oldtup.t_self), LockTupleNoKeyExclusive, LockWaitBlock, &have_tuple_lock);

在去拿xmax=745的事务锁,确保修改那个事务已经没了

XactLockTableWait(xwait, relation, &oldtup.t_self, XLTW_Update);

这里会加transactionid的ShareLock模式。

  • 746事务自己拿了一个transactionid ExclusiveLock因为自己也更新了数据。

  • 745事务有写入数据,所以745已经拿到transactionid的ExclusiveLock。

  • 746事务去获取745的transactionid ShareLock,开始等锁。

这里等锁就发生了,保证了RC级别的隔离性。

postgres=# select * from pg_locks where pid <> pg_backend_pid() order by pid,locktype;locktype    | database | relation | page | tuple | virtualxid | transactionid | classid | objid | objsubid | virtualtransaction |  pid  |       mode       | granted | fastpath |waitstart
---------------+----------+----------+------+-------+------------+---------------+---------+-------+----------+--------------------+-------+------------------+---------+----------+-------------------------------transactionid |          |          |      |       |            |           745 |         |       |          | 3/446              | 29044 | ExclusiveLock    | t       | f        |transactionid |          |          |      |       |            |           746 |         |       |          | 4/22               | 29246 | ExclusiveLock    | t       | f        |transactionid |          |          |      |       |            |           745 |         |       |          | 4/22               | 29246 | ShareLock        | f       | f        | xxxx-xx-xx 16:53:14.828479+08
  • 如果事务745发生了提交
    • 那么事务2就不应该更新3这条数据了。代码继续运行会检查oldtup.t_data,确认xmax到底有没有回滚。这里heap_update不会继续进行更新动作了,直接返回TM_Updated。外层函数ExecUpdate收到TM_Updated后,会调用EvalPlanQual重新读取这一行数据,如果还能看到就返回epqslot新元组下面重新更新;如果现在已经看不到这一行了,就返回NULL,这次的更新就结束了。
  • 如果事务745发生了回滚
    • 那么事务2就还能看到3这条数据。代码继续运行检查发现xmax已经回滚了,可以继续更新,所以在heap_update中完成了本次更新,返回TM_Ok。

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

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

相关文章

用Dockerfile创建PostgreSQL数据库

官网下载基本镜像 [rootlocalhost ~]# docker pull postgres:latest创建项目目录 [rootlocalhost ~]# mkdir /root/postgresql创建一个名为 “Dockerfile” 的文件 [rootlocalhost ~]# vim Dockerfile # 使用官方的PostgreSQL镜像 FROM postgres:latest# 设置环境变量&#…

10款ai文生图软件/网站推荐

1. Ai-Chat 推荐指数&#xff1a;⭐⭐⭐⭐ 链接&#xff1a; https://mmm.aiyujiang.com/ 上传图片并输入AI提示词就能一键生成各类动漫、卡通风格头像&#xff0c;算法强大&#xff0c;风格多样&#xff0c;一键开启你的AI自由创作之旅。有电脑版和手机版&#xff0c;也是很…

大数据信用报告查询方式一般有几种?哪种比较好?

在了解这个问题之前&#xff0c;想必你对大数据信用与人行信用的区别都是比较清楚了&#xff0c;本文呢就着重讲一下大数据信用报告查询方式有几种&#xff0c;哪种比较好&#xff0c;感兴趣的朋友不妨一起去看看。 大数据信用报告常见的三种查询方式&#xff1a; 一、二维码分…

手持三防平板丨国产化加固平板丨国产三防平板发展的意义是什么?

随着现代科技的快速发展&#xff0c;平板电脑在我们的生活中扮演着越来越重要的角色。然而&#xff0c;传统的平板电脑只能在普通的环境中使用&#xff0c;而无法在恶劣的环境中使用&#xff0c;例如在高海拔、高温、高湿度、沙漠等环境中&#xff0c;传统平板电脑往往会出现故…

目标检测教程视频指南大全

魔鬼面具-哔哩哔哩视频指南 必看干货系列(建议搞深度学习的小伙伴都看看,特别是图像相关) 深度学习常见实验问题与实验技巧(适用于所有模型&#xff0c;小白初学者必看!)还在迷茫深度学习中的改进实验应该从哪里开始改起的同学&#xff0c;一定要进来看看了&#xff01;用自身…

利用PaddleNLP进行文本数据脱敏

最近在脱敏一些客服数据&#xff0c;同事用正则进行了一些处理&#xff0c;但是感觉针对人名、数量等信息还是无法处理&#xff0c;例如“北方种植了很多李子树”&#xff0c;李子树有可能被识别为人名&#xff0c;又如“美国采购坦克1005台&#xff0c;价值4500万比索”&#…

图的遍历(广度优先遍历BFS,深度优先遍历DFS)

目录 图的遍历概念&#xff1a; 图的广度优先遍历&#xff08;BFS&#xff09;&#xff1a; 代码实现如下&#xff1a; 测试如下&#xff1a; 注意&#xff1a; 图的深度优先遍历&#xff08;DFS&#xff09;&#xff1a; 代码实现如下&#xff1a; 测试如下&#xff1…

Web服务器基础

Web服务器基础 【一】前端概述 【1】HTML HTML&#xff08;超文本标记语言&#xff09;是用于创建网页结构的标记语言。它定义了网页的骨架&#xff0c;包括标题、段落、列表、链接等元素&#xff0c;但没有样式。可以将HTML视为网页的结构和内容的描述。 【2】CSS css&…

阿里云服务器镜像是什么?如何选择镜像?

阿里云服务器镜像怎么选择&#xff1f;云服务器操作系统镜像分为Linux和Windows两大类&#xff0c;Linux可以选择Alibaba Cloud Linux&#xff0c;Windows可以选择Windows Server 2022数据中心版64位中文版&#xff0c;阿里云服务器网aliyunfuwuqi.com来详细说下阿里云服务器操…

Go 是否有三元运算符?Rust 和 Python 是怎么做的?

嗨&#xff0c;大家好&#xff01;本文是系列文章 Go 技巧第十四篇&#xff0c;系列文章查看&#xff1a;Go 语言技巧。 今天来聊聊在 Go 语言中是否支持三元运算符。这个问题很简单&#xff0c;没有。 首先&#xff0c;什么是三元运算符&#xff1f; 在其他一些编程语言中&a…

MySQL篇之分库分表

一、为什么要分库分表 1.目的 1. 分担了访问压力 2. 解决存储压力 2.分库分表的时机 1. 前提&#xff0c;项目业务数据逐渐增多&#xff0c;或业务发展迅速&#xff0c;单表的数据量达1000W或20G以后。 2. 优化已解决不了性能问题&#xff08;主从读写分离、查询索引…&am…

Python | Conda常用命令

一、介绍 1、Anaconda工具 Anaconda是一个用于数据科学和机器学习的开源软件包管理器和环境管理器。它包含了许多流行的数据科学工具和库&#xff0c;如Python、Jupyter Notebook、numpy、pandas、scikit-learn等&#xff0c;可以帮助用户轻松地管理和安装这些工具和库。Anaco…

数据库管理-第152期 Oracle Vector DB AI-04(20240220)

数据库管理152期 2024-02-20 数据库管理-第152期 Oracle Vector DB & AI-04&#xff08;20240220&#xff09;1 常用的向量检索方法聚类图搜索哈希量化 2 Oracle Vector DB中的索引索引&#xff08;默认&#xff09; 索引&#xff08;高级&#xff09;3 EMBEDDINGSSQL EMBE…

masscan使用

masscan简介: masscan 是一种快速的端口扫描工具&#xff0c;旨在快速扫描大量IP地址和端口。masscan的发包速度非常快&#xff0c;在windows中&#xff0c;它的发包速度可以达到每秒30万包&#xff1b;在Linux中&#xff0c;速度可以达到每秒160万。masscan在扫描时会随机选择…

阿里云备案服务器买哪种?多少钱?有什么限制条件?

在阿里云备案服务器需要多少钱&#xff1f;目前符合备案条件的阿里云服务器只要30元&#xff0c;并且这台云服务器可以备案5个网站。2核4G配置&#xff0c;价格为30元3个月&#xff0c;也可以选择2核2G轻量服务器&#xff0c;61元一年&#xff0c;阿里云老用户还可以选择99元一…

通俗易懂地理解稀疏性

今天我想与大家探讨的是一个数学和工程学中的重要概念——稀疏性。这个概念可能听起来很抽象&#xff0c;但它实际上贯穿于我们生活中的许多方面。那么&#xff0c;稀疏性到底是什么呢&#xff1f;简单来说&#xff0c;在数学和信号处理领域&#xff0c;一个信号被称为稀疏&…

vue小记——this

原生和Vue中使用this的这几个坑你都知道吗&#xff1f; - 掘金 (juejin.cn) 在JavaScript中&#xff0c;this是一个特殊的关键字&#xff0c;它在函数被调用时自动定义。this的值在函数被调用时决定&#xff0c;取决于调用的上下文&#xff08;context&#xff09;&#xff0c…

Eclipse - Text Editors (文本编辑器)

Eclipse - Text Editors [文本编辑器] References Window -> Preferences -> General -> Editors -> Text Editors Displayed tab witdth: 4 勾选 Insert spaces for tabs 勾选 Show line number References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.n…

力扣(LeetCode)数据结构练习题(2)

今天又写了两道关于链表的练习题&#xff0c;来给大家分享一下。巩固一下上一篇学到的链表知识&#xff0c;题目可以然我们更清楚的认识链表。 目录 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表 给你单链表的头结点 head &#xff0c;请…

ADO.NET事务处理

在ADO.NET中&#xff0c;事务是一组一起执行的数据库操作&#xff0c;这些操作要么全部成功&#xff0c;要么全部失败。这确保了数据库的一致性和完整性。ADO.NET提供了SqlTransaction类来支持事务处理。 以下是一个使用C#和ADO.NET进行事务处理的示例&#xff1a; csharp代码…