PostgreSQL 中如何处理数据的并发更新冲突解决?

文章目录

  • 一、并发更新冲突的场景
  • 二、PostgreSQL 中的并发控制机制
    • (一) 封锁机制
    • (二) 事务隔离级别
  • 三、并发更新冲突的解决方法
    • (一) 重试机制
    • (二) 使用乐观并发控制
    • (三) 使用悲观并发控制
    • (四) 应用版本字段
    • (五) 基于时间戳的冲突解决
  • 四、实际应用中的考虑因素
    • (一) 性能影响
    • (二) 业务逻辑适应性
    • (三) 数据分布和访问模式
  • 五、示例分析

美丽的分割线

PostgreSQL


在数据库并发操作环境中,多个事务同时尝试更新相同的数据可能导致冲突。PostgreSQL 提供了一系列机制来处理这些并发更新冲突,以确保数据的一致性和完整性。

美丽的分割线

一、并发更新冲突的场景

当两个或多个事务同时尝试对同一行数据进行修改时,就可能发生并发更新冲突。常见的场景包括:

  1. 同时修改同一行的不同列
  2. 同时对同一列进行不同的值更新

美丽的分割线

二、PostgreSQL 中的并发控制机制

PostgreSQL 主要使用 MVCC(多版本并发控制,Multiversion Concurrency Control ) 来处理并发事务。MVCC 允许事务读取到符合其隔离级别需求的数据版本,而不需要加锁阻塞其他事务的读操作。然而,在写操作时,仍可能出现冲突。

(一) 封锁机制

PostgreSQL 使用多种类型的锁来控制对数据的并发访问。常见的锁类型包括:

  1. 共享锁(Shared Lock):允许其他事务也获取共享锁,但阻止获取排他锁。常用于读取操作。
  2. 排他锁(Exclusive Lock):阻止其他事务获取任何类型的锁,常用于写入操作。

锁的粒度可以是行级(Row-Level)、页级(Page-Level)和表级(Table-Level)。

(二) 事务隔离级别

PostgreSQL 支持四种事务隔离级别:

  1. 读未提交(Read Uncommitted):这是最低的隔离级别,一个事务可以读取到其他事务未提交的数据修改,可能导致脏读、不可重复读和幻读等问题。
  2. 读已提交(Read Committed):事务只能读取已经提交的数据,避免了脏读,但仍可能出现不可重复读和幻读。
  3. 可重复读(Repeatable Read):在一个事务内多次读取相同的数据会得到相同的结果,避免了不可重复读,但可能出现幻读。
  4. 串行化(Serializable):最高的隔离级别,通过严格的并发控制确保事务的串行执行,避免了脏读、不可重复读和幻读。

美丽的分割线

三、并发更新冲突的解决方法

(一) 重试机制

一种简单的方法是当冲突发生时,让事务进行重试。示例如下:

DO
$$
DECLAREconflict_detected BOOLEAN := FALSE;
BEGINLOOP-- 尝试执行更新操作UPDATE products SET price = 100 WHERE id = 1;-- 检查是否有冲突(例如,通过检查受影响的行数)IF NOT FOUND THENconflict_detected := TRUE;ELSEEXIT;END IF;-- 若有冲突,等待一段时间并重试IF conflict_detected THENPERFORM pg_sleep(1);END IF;END LOOP;
END;
$$;

在上述示例中,如果更新操作没有影响到任何行(表示可能存在冲突),则设置一个标志,等待一段时间后重试。

(二) 使用乐观并发控制

乐观并发控制假设并发冲突很少发生。在这种方式中,事务在更新数据时不进行加锁,而是在提交时检查数据是否被其他事务修改。如果没有冲突,事务成功提交;如果有冲突,事务回滚并根据需要重试。

-- 获取数据的初始版本
SELECT price AS original_price FROM products WHERE id = 1;-- 进行业务处理和修改
UPDATE products SET price = 100 WHERE id = 1 AND price = original_price;

在上述示例中,更新操作仅在数据未被其他事务修改的情况下成功。

(三) 使用悲观并发控制

悲观并发控制则假设并发冲突很可能发生,在事务执行期间获取所需的锁来阻塞其他可能冲突的事务。

BEGIN;-- 获取排他锁
LOCK TABLE products IN SHARE ROW EXCLUSIVE MODE;-- 进行数据更新
UPDATE products SET price = 100 WHERE id = 1;COMMIT;

(四) 应用版本字段

给表添加一个版本字段来跟踪数据的更改。

CREATE TABLE products (id SERIAL PRIMARY KEY,price DECIMAL(10, 2),version INT DEFAULT 0
);

在更新数据时,同时递增版本字段:

UPDATE products SET price = 100, version = version + 1 WHERE id = 1 AND version = <expected_version>;

如果更新影响的行数为 0,表示存在冲突,因为预期的版本与实际的版本不一致。

(五) 基于时间戳的冲突解决

为每行数据添加一个时间戳字段,记录数据的最后修改时间。

CREATE TABLE products (id SERIAL PRIMARY KEY,price DECIMAL(10, 2),last_modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

在更新时,仅更新时间戳比当前事务读取的时间戳更早的数据:

UPDATE products SET price = 100 WHERE id = 1 AND last_modified <= <read_timestamp>;

美丽的分割线

四、实际应用中的考虑因素

(一) 性能影响

  1. 不同的冲突解决方法对数据库性能有不同的影响。例如,使用封锁可能导致其他事务的等待,增加系统的阻塞时间,从而影响并发性。而乐观并发控制在冲突很少发生时性能较好,但在冲突频繁时可能导致大量的事务重试,增加了总体的执行时间。
  2. 应用版本字段或基于时间戳的方法可能需要额外的存储空间来维护版本或时间戳信息,并在更新时进行额外的判断和处理。

(二) 业务逻辑适应性

  1. 某些业务场景可能更适合某种特定的冲突解决方法。例如,如果业务对数据的一致性要求非常高,不能容忍任何不一致的情况,那么悲观并发控制或串行化隔离级别可能是更好的选择。
  2. 对于冲突不太频繁且对响应时间要求较高的场景,乐观并发控制可能更合适。

(三) 数据分布和访问模式

  1. 如果数据的访问是高度并发的,并且多个事务经常同时访问相同的数据行,那么需要更加谨慎地选择冲突解决方法,以避免过度的阻塞和冲突。
  2. 对于数据分布较为均匀,冲突概率较低的情况,可以采用相对简单和高效的方法,如乐观并发控制。

美丽的分割线

五、示例分析

假设我们有一个在线商店的库存管理系统,其中有一个 inventory 表来存储商品的库存数量。

CREATE TABLE inventory (product_id INT PRIMARY KEY,quantity INT,last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

现在有两个并发的事务:

事务 1:

BEGIN;
SELECT * FROM inventory WHERE product_id = 1;
-- 假设读取到的数量为 10
UPDATE inventory SET quantity = 5 WHERE product_id = 1 AND last_updated <= <read_timestamp>;
COMMIT;

事务 2:

BEGIN;
SELECT * FROM inventory WHERE product_id = 1;
-- 假设也读取到的数量为 10
UPDATE inventory SET quantity = 8 WHERE product_id = 1 AND last_updated <= <read_timestamp>;
COMMIT;

如果这两个事务几乎同时执行,可能会发生冲突。

如果我们采用基于时间戳的冲突解决方法:

  1. 事务 1 读取数据时获取了当前的时间戳(T1)。
  2. 事务 2 读取数据时获取了稍晚的时间戳(T2)。

当事务 1 尝试更新时,如果自它读取以来没有其他事务修改数据(即 last_updated <= T1),则更新成功。

当事务 2 尝试更新时,如果发现数据的 last_updated 大于 T2(说明在事务 2 读取之后被修改过),则更新失败,事务 2 可以选择回滚并重试,或者根据业务逻辑进行其他处理。


美丽的分割线

🎉相关推荐

  • 🍅关注博主🎗️ 带你畅游技术世界,不错过每一次成长机会!
  • 📚领书:PostgreSQL 入门到精通.pdf
  • 📙PostgreSQL 中文手册
  • 📘PostgreSQL 技术专栏

PostgreSQL

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

用这款免费爬虫神器,不用手动撸代码了!

很多人学习Python和我说是为了“爬虫”&#xff0c;爬虫的用处确实很丰富&#xff0c;如&#xff1a; 市场研究&#xff0c;了解竞争对手信息&#xff0c;爬虫收集舆论信息、产品动态。 价格分析&#xff0c;通过抓取不同平台商品价格&#xff0c;监测价格波动&#xff0c;…

PDManer使用教程及安装包

以下安装包版本比较低&#xff0c;用习惯了&#xff0c;需要高版本可以去官网下载 链接&#xff1a;https://pan.baidu.com/s/1Hj4zJ0UCcdk0YQTlteVCTQ?pwdv72v 提取码&#xff1a;v72v 使用教程 连接数据库 导入表信息 创建关系图 第一步 第二步 如果列显示不全 &#x…

【LLM大模型】机器学习导论(西瓜书)[推荐阅读]

哈喽啊大家&#xff0c;今天又来给大家推荐一本机器学习方面的书籍<机器学习西瓜书>。本书作为该领域的入门教材&#xff0c;在内容上尽可能涵盖机器学习基础知识的各方面。 为了使尽可能多的读者通过本书对机器学习有所了解&#xff0c;作者试图尽可能少地使用数学知识…

【内网渗透】MSF渗透阶段的常用指令笔记

目录 渗透阶段划分 msfvenom 常用参数 各平台生成payload命令 Meterpreter Meterpreter的常用命令 基本命令 常用命令 针对安卓手机的一些命令 针对Windows的一些命令 文件系统命令 生成木马反弹shell(以linux靶机为例) 木马生成 配置监控 攻击利用 辅助模块 怎…

QT TCP多线程网络通信

学习目标&#xff1a; TCP网络通信编程 学习前置环境 运行环境:qt creator 4.12 QT TCP网络通信编程-CSDN博客 Qt 线程 QThread类详解-CSDN博客 学习内容 使用多线程技术实现服务端计数器 核心代码 客户端 客户端&#xff1a;负责连接服务端&#xff0c;每次连接次数1。…

从零开始做题:MP3

题目 给出一个mp3文件 解题 右键->selection->save selection->另存为xxx.png即可 8750d5109208213f E:\逐鹿\MISC\tools\MP3Stego_1_1_19\MP3Stego>.\decode -X cipher.mp3 MP3StegoEncoder 1.1.19 See README file for copyright info Input file cipher.mp3…

秒懂设计模式--学习笔记(8)【结构型-组合模式】

目录 7、组合模式7.1 组合模式&#xff08;Composite&#xff09;7.2 叉树结构7.3 文件系统7.4 目录树展示7.5 自相似性的涌现7.6 组合模式的各角色定义7.7 组合 7、组合模式 7.1 组合模式&#xff08;Composite&#xff09; 是针对由多个节点对象&#xff08;部分&#xff0…

centos部署jar包

第一步&#xff1a; 将IDEA中的项目打包为jar,将这个jar文件放到centos服务器上的目录里&#xff0c;我在opt新建api目录&#xff0c;将jar文件放入&#xff0c;如下图&#xff1a; 第二步&#xff1a; 将需要读取的配置文件也放入此目录(其他目录也可以&#xff0c;和脚本中…

Thread类的start()方法和run()方法的区别

在Java多线程编程中&#xff0c;Thread类是一个非常重要的类&#xff0c;它提供了创建和管理线程的能力。对于初学者来说&#xff0c;理解Thread类的start()方法和run()方法之间的区别尤为重要。本文将深入探讨这两者之间的不同&#xff0c;帮助读者更好地掌握Java多线程编程的…

web端的vscode编辑器

下载code-server到本地 略 参考 https://blog.csdn.net/kfashfasf/article/details/137110668 运行code-server 到用户目录下设置 vim ~/.config/code-server/config.yaml . bind-addr: 0.0.0.0:8080 auth: password password: xxxxxx cert: false运行 [centosamazon22 ~…

中职网络安全wire0077数据包分析

从靶机服务器的FTP上下载wire0077.pcap&#xff0c;分析该文件&#xff0c;找出黑客入侵使用的协议&#xff0c;提交协议名称 SMTP 分析该文件&#xff0c;找出黑客入侵获取的zip压缩包&#xff0c;提交压缩包文件名 DESKTOP-M1JC4XX_2020_09_24_22_43_12.zip 分析该文件&…

使用Godot4组件制作竖版太空射击游戏_2D卷轴飞机射击-滚动背景(四)

文章目录 开发思路开发思路 使用Godot4组件制作竖版太空射击游戏_2D卷轴飞机射击&#xff08;一&#xff09; 使用Godot4组件制作竖版太空射击游戏_2D卷轴飞机射击-激光组件&#xff08;二&#xff09; 使用Godot4组件制作竖版太空射击游戏_2D卷轴飞机射击-飞船动画&#xff08…

pytorch-RNN实战-正弦曲线预测

目录 1. 正弦数据生成2. 构建网络3. 训练4. 预测5. 完整代码6. 结果展示 1. 正弦数据生成 曲线如下图&#xff1a; 代码如下图&#xff1a; 50个点构成一个正弦曲线随机生成一个0~3之间的一个值&#xff08;随机的原因是防止每次都从相同的点开始&#xff0c;50个点的正弦曲…

JavaSE 面向对象程序设计进阶 IO流 字节流详解 抛出异常

input output 像水流一样读取数据 存储和读取数据的解决方案 内存中数据不能永久化存储 程序停止运行 数据消失 File只能对文件本身进行操作 不能读写文件里存储的数据 读写数据必须要有IO流 可以把程序中的数据保存到文件当中 还可以把本地文件中的数据读取到数据当中 分…

白酒营销策划全攻略:从市场调研到执行落地的实战指南!

为白酒品牌做营销策划&#xff0c;那可得像给自家的孩子挑衣服一样&#xff0c;得量身定制&#xff0c;得考虑孩子的身材、喜好&#xff0c;还得看看衣服的款式和布料。 这里可以分享一点自己多年的实战干货给你&#xff0c;希望对你有所帮助。 首先&#xff0c;得做好“侦查…

【常见开源库的二次开发】一文学懂CJSON

简介&#xff1a; JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式。它基于JavaScript的一个子集&#xff0c;但是JSON是独立于语言的&#xff0c;这意味着尽管JSON是由JavaScript语法衍生出来的&#xff0c;它可以被任何编程语言读取和生成…

CentOS7系统上安装MySQL8.0(rpm-bundle.tar)详细过程

一、MySQL官网下载安装包 1.进入官网MySQL :: Download MySQL Community Server 2.查看自己的版本和架构 uname -mcat /etc/redhat-release 3.选择对应版本并下载 4.查看linux自带的mariadb数据库&#xff0c;有就卸载掉。 rpm -qa | grep mariadbrpm -e mariadb-libs…

【卡尔曼滤波】高斯白噪声

生成高斯白噪声并将其应用于信号处理 生成高斯白噪声并将其应用于信号处理 #以下是一个生成高斯白噪声并将其应用于信号处理的示例代码:import numpy as np import matplotlib.pyplot as plt import matplotlib.font_manager ## not work#notice matplotlibrc is a file, not…

学生选课管理系统(Java+MySQL)

技术栈 Java: 用于实现系统的核心业务逻辑。MySQL: 作为关系型数据库&#xff0c;用于存储系统中的数据。JDBC: 用于Java程序与MySQL数据库之间的连接和交互。Swing GUI: 用于创建图形用户界面&#xff0c;提升用户体验。 系统功能 我们的学生选课管理系统主要针对学生和管理…

突破传统:实现智慧校园实习单位变更

在智慧校园的实习管理系统设计中&#xff0c;充分考虑到了实习阶段学生可能遇到的实际需求&#xff0c;特别是实习单位变更这一灵活性要求&#xff0c;系统特设了一套完善的在线处理机制&#xff0c;旨在促进学生、学校与企业间的顺畅沟通与协调&#xff0c;确保实习过程的平稳…