Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
PHP与MySQL多并发更新中的竞态条件:解决默认卡片设置问题_创想鸟

PHP与MySQL多并发更新中的竞态条件:解决默认卡片设置问题

PHP与MySQL多并发更新中的竞态条件:解决默认卡片设置问题

本文探讨了在php与mysql应用中,多并发请求导致数据库出现竞态条件,造成多个默认卡片的问题。我们将分析问题根源,并重点介绍如何利用数据库事务确保数据更新的原子性与一致性,从而有效避免此类数据不一致性。文章还将提及其他并发控制策略,以提供全面的解决方案。

在现代Web应用中,处理用户并发请求是常见的场景。然而,如果不加以适当的并发控制,这些并发请求可能导致数据不一致,即所谓的“竞态条件”(Race Condition)。一个典型的例子是,在一个用户拥有多张卡片,且其中一张必须被设为默认卡片的系统中,当用户同时发起多个请求来更改默认卡片时,可能最终导致出现多张默认卡片,这显然违背了业务逻辑。

理解竞态条件与数据不一致性

假设我们有一个cards表,其中包含id、user_id和is_default字段。is_default字段为布尔值,表示该卡片是否为默认卡片。业务规则规定,每个用户只能有一张默认卡片。

以下是初始表结构示例:

id user_id is_default

15002501

当用户ID为50的用户同时发起两个请求,分别将卡片1和卡片2设为默认时,问题便会浮现:

立即学习“PHP免费学习笔记(深入)”;

PATCH http://localhost:8000/cards/1/defaultPATCH http://localhost:8000/cards/2/default

在没有并发控制的情况下,后端代码可能如下所示:

use AppModelsCard;use IlluminateHttpRequest;public function setAsDefault(Request $request, $id){  // 步骤1: 将该用户所有卡片设为非默认  Card::where('user_id', $request->user()->id)->update(['is_default' => false]);  // 步骤2: 将指定卡片设为默认  Card::where([    'id' => $id,    'user_id' => $request->user()->id  ])->update(['is_default' => true]);  return ['status' => true];}

当两个请求几乎同时执行时,可能发生以下时序:

请求A 执行 Card::where(‘user_id’, $request->user()->id)->update([‘is_default’ => false]); (将所有卡片设为非默认)。请求B 执行 Card::where(‘user_id’, $request->user()->id)->update([‘is_default’ => false]); (将所有卡片设为非默认)。请求A 执行 Card::where([‘id’ => 1, ‘user_id’ => $request->user()->id])->update([‘is_default’ => true]); (将卡片1设为默认)。请求B 执行 Card::where([‘id’ => 2, ‘user_id’ => $request->user()->id])->update([‘is_default’ => true]); (将卡片2设为默认)。

最终结果是卡片1和卡片2都被设为默认,导致数据不一致:

id user_id is_default

15012501

问题在于,这两步数据库操作(先清空所有默认,再设置新的默认)并非原子性的。在多个请求并发执行时,它们会交错进行,从而破坏了操作的完整性。

利用数据库事务解决竞态条件

解决这类竞态条件最有效且常用的方法是使用数据库事务(Transactions)。事务确保一组数据库操作要么全部成功提交,要么全部失败回滚,从而保证了操作的原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability),即ACID特性。

在Laravel框架中,我们可以很方便地使用DB::transaction方法来定义事务块。将上述两步更新操作包裹在一个事务中,可以确保它们作为一个单一的、不可分割的逻辑单元执行。

use AppModelsCard;use IlluminateHttpRequest;use IlluminateSupportFacadesDB; // 引入DB门面public function setAsDefault(Request $request, $id){    try {        DB::transaction(function() use ($request, $id) {            // 步骤1: 将该用户所有卡片设为非默认            Card::where('user_id', $request->user()->id)                  ->update(['is_default' => false]);            // 步骤2: 将指定卡片设为默认            Card::where([                'id' => $id,                'user_id' => $request->user()->id            ])->update(['is_default' => true]);        });        return ['status' => true];    } catch (Exception $e) {        // 事务失败,回滚        // 记录错误或返回失败信息        return ['status' => false, 'message' => $e->getMessage()];    }}

工作原理:

当第一个请求进入事务块时,它会锁定相关的资源(或在某些隔离级别下,通过其他机制保证隔离)。在事务提交之前,其他并发请求将无法看到或修改该事务正在操作的数据,或者它们会被阻塞,直到第一个事务完成。这样,无论多少个请求同时尝试设置默认卡片,数据库系统都会确保这些操作串行化地执行,从而避免了中间状态的暴露和数据不一致。

例如,如果请求A先进入事务并开始执行,请求B在几乎同时到达时,它会等待请求A的事务完成。一旦请求A的事务提交,卡片1被设为默认,而所有其他卡片(包括卡片2)都被设为非默认。此时,请求B的事务开始执行,它会首先将所有卡片(包括卡片1)设为非默认,然后再将卡片2设为默认。最终,只有卡片2是默认卡片,保证了数据的一致性。

其他并发控制策略

除了数据库事务,还有其他一些方法可以在特定场景下辅助解决并发问题,但它们通常不能完全替代事务在数据一致性方面的作用。

悲观锁(Pessimistic Locking)悲观锁是一种在读取数据时就加锁的策略,防止其他事务修改或读取相同数据,直到当前事务完成。在某些复杂的业务逻辑中,如果需要先查询数据再进行更新,并且希望在查询阶段就阻止其他事务修改,悲观锁会很有用。

例如,在Laravel中,可以使用sharedLock()(共享锁,允许其他事务读取但不能写入)或lockForUpdate()(排他锁,阻止其他事务读取和写入)方法:

DB::transaction(function () use ($request, $id) {    // 获取当前用户的所有卡片并加排他锁    // 这会阻塞其他尝试修改这些卡片的事务    $cards = Card::where('user_id', $request->user()->id)                 ->lockForUpdate()                 ->get();    foreach ($cards as $card) {        $card->is_default = false;        $card->save();    }    $targetCard = Card::find($id);    if ($targetCard && $targetCard->user_id == $request->user()->id) {        $targetCard->is_default = true;        $targetCard->save();    }});

这种方式在某些情况下比直接的update操作更细粒度,但也会增加数据库的锁竞争,可能影响并发性能。对于本例中的简单update操作,数据库事务本身通常已足够,因为UPDATE语句在执行时,数据库自身会处理必要的行锁。

速率限制(Rate Limiting)速率限制是一种在应用层限制用户或IP地址在特定时间段内发起请求数量的策略。它不能直接解决数据库层面的竞态条件,但可以从源头减少并发请求的数量,从而降低竞态条件发生的概率。

在Laravel中,可以通过路由中间件轻松实现速率限制:

// 在 routes/api.php 中Route::middleware('throttle:60,1')->group(function () {    Route::patch('/cards/{id}/default', [CardController::class, 'setAsDefault']);});

这表示该路由每分钟最多允许60个请求。虽然速率限制有助于防止滥用和减轻服务器压力,但它并不能保证数据的一致性,如果两个请求在允许的速率限制内几乎同时到达,竞态条件仍然可能发生。因此,速率限制应作为辅助手段,与数据库事务结合使用。

总结与最佳实践

处理多并发更新中的竞态条件是构建健壮应用的关键。对于涉及多个相互依赖的数据库操作,并且需要确保这些操作要么全部成功、要么全部失败的场景,数据库事务是首选且最可靠的解决方案。

核心要点:

识别原子性操作: 任何一组必须作为一个单一逻辑单元执行的数据库操作都应封装在事务中。使用数据库事务: 利用框架提供的事务API(如Laravel的DB::transaction)来保证数据的一致性。异常处理: 在事务中捕获异常,以便在操作失败时能够正确回滚事务并处理错误。考虑隔离级别: 了解数据库的事务隔离级别(如READ COMMITTED、REPEATABLE READ等),它们会影响事务的并发行为。对于大多数Web应用,默认的隔离级别通常足够,但对于极端高并发或复杂场景,可能需要进行调整。辅助策略: 速率限制可以作为预防措施,减少并发请求的压力,但不能替代事务在数据一致性方面的作用。悲观锁适用于需要更精细控制读写冲突的场景。

通过恰当地应用数据库事务,我们可以有效地防止因并发操作导致的数据不一致问题,确保应用程序的数据完整性和可靠性。

以上就是PHP与MySQL多并发更新中的竞态条件:解决默认卡片设置问题的详细内容,更多请关注php中文网其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1326106.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
PHP代码如何操作数组元素_PHP数组遍历与常用数组函数使用指南
上一篇 2025年12月12日 12:36:07
WordPress开发:优雅地在文章标题前插入特色图片(避免后台显示问题)
下一篇 2025年12月12日 12:36:24

相关推荐

  • 利用AWS Pinpoint高效发送注册验证码(OTP)教程

    利用AWS Pinpoint高效发送注册验证码(OTP)教程利用AWS Pinpoint高效发送注册验证码(OTP)教程利用AWS Pinpoint高效发送注册验证码(OTP)教程利用AWS Pinpoint高效发送注册验证码(OTP)教程

    本文旨在指导开发者如何高效利用AWS Pinpoint服务发送用户注册验证码(OTP),解决传统AWS SNS在处理动态、未预注册手机号时的局限性。我们将深入探讨Pinpoint作为首选方案的优势,提供具体实现步骤和代码示例,并分享最佳实践,确保OTP消息的可靠、快速送达。 理解注册验证码(OTP)…

    2026年9月25日 • 用户投稿
    000
  • 淘宝消息提醒收不到怎么办 通知功能设置与优化方法

    淘宝消息提醒收不到怎么办 通知功能设置与优化方法淘宝消息提醒收不到怎么办 通知功能设置与优化方法淘宝消息提醒收不到怎么办 通知功能设置与优化方法淘宝消息提醒收不到怎么办 通知功能设置与优化方法

    先检查手机系统通知权限,再开启淘宝App内消息提醒开关,最后确保网络稳定并允许后台运行,三步解决收不到消息问题。 收不到淘宝消息提醒,问题通常出在App权限或内部设置没开。先检查手机系统是否禁止了通知,再进淘宝里开启对应开关,基本都能解决。 检查手机系统通知权限 如果手机系统没给淘宝发通知的权限,A…

    2026年9月25日 • 用户投稿
    000
  • mysql数据库怎么创建数据

    mysql数据库怎么创建数据mysql数据库怎么创建数据mysql数据库怎么创建数据mysql数据库怎么创建数据

    在 MySQL 数据库中创建数据涉及以下步骤:连接到数据库并选择目标数据库。使用 CREATE TABLE 语句创建数据表。使用 INSERT INTO 语句插入数据。使用 COMMIT 语句提交更改。 如何在 MySQL 数据库中创建数据 在 MySQL 数据库中创建数据是一个简单而直接的过程。以…

    2026年9月25日 • 用户投稿
    000
  • yii框架如何安装

    yii框架如何安装yii框架如何安装yii框架如何安装yii框架如何安装

    通过 Composer 安装 安装 Composer                   (推荐学习:yii教程) 如果还没有安装 Composer,你可以按 getcomposer.org 中的方法安装。  在 Linux 和 Mac OS X 中可以运行如下命令: curl -sS https:…

    2026年9月25日 • 用户投稿
    000
  • DWG转DXF为何非真彩色

    DWG转DXF为何非真彩色DWG转DXF为何非真彩色DWG转DXF为何非真彩色DWG转DXF为何非真彩色

    1、 null 2、 当在CAD中将DWG文件转换为DXF格式时,若发现对象颜色未保留真彩色,可能是因为打印配置中应用了monochrome.ctb样式表,该设置会强制输出为黑白图形,而非原始彩色。 3、 在导出至ACAD格式时,可利用图层映射功能,将SolidWorks中的不同对象指派到特定图层,…

    2026年9月25日 • 用户投稿
    000
  • mysql怎么插数据命令行语句

    如何使用 mysql 命令行插入数据 在 MySQL 中,可以使用以下 INSERT 语句将数据插入到数据库中: INSERT INTO table_name (column1, column2, …) VALUES (value1, value2, …); 其中: table_name 是…

    2026年9月25日
    100
  • Hibernate/Spring Boot中复合主键与多对多关联的实现指南

    Hibernate/Spring Boot中复合主键与多对多关联的实现指南Hibernate/Spring Boot中复合主键与多对多关联的实现指南Hibernate/Spring Boot中复合主键与多对多关联的实现指南Hibernate/Spring Boot中复合主键与多对多关联的实现指南

    本教程详细阐述了在Spring Boot和Hibernate框架中,如何优雅地处理具有附加属性的多对多关系,特别是当连接表需要复合主键时。我们将通过构建一个用户电影评分系统为例,深入探讨@EmbeddedId、@Embeddable以及@OneToMany、@ManyToOne等JPA注解的实际应用…

    2026年9月25日 • 用户投稿
    000
  • 【新手入门】使用ERNIE-4.5-0.3B-Paddle从原始文本构建知识图谱

    1. 概述 本文将探讨如何使用ernie-4.5-0.3b-paddle模型从原始文本构建知识图谱。通过结合大语言模型(llm)和检索增强生成(rag)技术实现文本生成,帮助我们从非结构化数据中高效提取实体和关系信息。 2. 什么是知识图谱? 2.1 基本概念 知识图谱是一种语义网络,它表示和连接现…

    2026年9月25日
    000
  • 淘宝搜索图片入口在哪里?如何推广店铺?淘宝商家必读:快速找到搜索图片入口及高效推广店铺指南

    淘宝搜索图片入口在哪里?如何推广店铺?淘宝商家必读:快速找到搜索图片入口及高效推广店铺指南淘宝搜索图片入口在哪里?如何推广店铺?淘宝商家必读:快速找到搜索图片入口及高效推广店铺指南淘宝搜索图片入口在哪里?如何推广店铺?淘宝商家必读:快速找到搜索图片入口及高效推广店铺指南淘宝搜索图片入口在哪里?如何推广店铺?淘宝商家必读:快速找到搜索图片入口及高效推广店铺指南

    在淘宝平台实现精准流量获取是商家运营的核心环节,而图片搜索功能让用户能够通过上传商品图片快速找到同款商品,为店铺带来了极具价值的曝光机会。本文将全面介绍图片搜索的入口位置,并深入分享7大关键推广策略,助力店铺有效提升转化率。 一、淘宝图片搜索入口详解 1.1 手机端操作方式 打开淘宝APP → 点击…

    2026年9月25日 • 用户投稿
    300
  • 解决Android Studio Gradle构建问题的网络仓库配置指南

    解决Android Studio Gradle构建问题的网络仓库配置指南解决Android Studio Gradle构建问题的网络仓库配置指南解决Android Studio Gradle构建问题的网络仓库配置指南解决Android Studio Gradle构建问题的网络仓库配置指南

    本文旨在解决Android Studio项目中因网络限制导致的Gradle构建失败问题,特别是“插件未找到”等错误。核心解决方案是通过配置替代的Maven仓库(如阿里云镜像)来绕过网络障碍,确保Gradle能够成功解析和下载所需的插件与依赖,从而恢复项目的正常构建。 1. 问题背景与常见症状 在an…

    2026年9月25日 • 用户投稿
    000
  • mysql创建数据库提示已存在怎么回事

    mysql创建数据库提示已存在怎么回事mysql创建数据库提示已存在怎么回事mysql创建数据库提示已存在怎么回事mysql创建数据库提示已存在怎么回事

    MySQL 创建数据库提示已存在的原因包括:数据库名称冲突、大小写敏感性、特殊字符限制、连接错误、权限问题、命名冲突和表名冲突。请检查并解决这些潜在原因。 MySQL 创建数据库提示已存在的原因 创建 MySQL 数据库时出现 “已存在” 提示,通常有以下几个原因: 1. 数…

    2026年9月25日 • 用户投稿
    000
  • MAC怎么快速切换不同的音频输出设备_Mac菜单栏音量图标切换声音输出

    MAC怎么快速切换不同的音频输出设备_Mac菜单栏音量图标切换声音输出MAC怎么快速切换不同的音频输出设备_Mac菜单栏音量图标切换声音输出MAC怎么快速切换不同的音频输出设备_Mac菜单栏音量图标切换声音输出MAC怎么快速切换不同的音频输出设备_Mac菜单栏音量图标切换声音输出

    通过菜单栏音量图标可快速切换音频输出设备,点击音量图标并选择目标设备即可生效;2. 使用快捷键与自动化工具如Keyboard Maestro或快捷指令创建AppleScript脚本,一键切换指定设备;3. 进入系统设置→声音→输出,手动选择设备,适用于初次配置或排查问题。 如果您在Mac上连接了多个…

    2026年9月25日 • 用户投稿
    100
  • PHP一键环境如何配置Memcached_Memcached缓存集成

    首先安装Memcached服务并启动,然后启用PHP的memcached扩展并重启服务,最后通过PHP代码连接并测试缓存读写;具体步骤包括:Windows或Linux系统下安装Memcached服务,确保端口11211监听;在宝塔等环境中安装php-memcached扩展并确认phpinfo显示模块…

    2026年9月25日
    000
  • mysql增删改查语句在哪写

    mysql增删改查语句在哪写mysql增删改查语句在哪写mysql增删改查语句在哪写mysql增删改查语句在哪写

    MySQL 增刪改查語句通常寫在以下位置:SQL 客户端(例如 MySQL Workbench)程式碼中外部檔案儲存程序 MySQL 增刪改查語句在哪裡寫? MySQL 增刪改查語句通常寫在以下位置: 1. SQL 客户端 例如,MySQL Workbench、phpMyAdmin 或命令行界面 (…

    2026年9月25日 • 用户投稿
    000
  • 漫番漫画官网直达_ 漫番漫画在线网页入口

    漫番漫画官网直达_ 漫番漫画在线网页入口漫番漫画官网直达_ 漫番漫画在线网页入口漫番漫画官网直达_ 漫番漫画在线网页入口漫番漫画官网直达_ 漫番漫画在线网页入口

    漫番漫画官网入口为https://manwa.me,平台汇聚冒险、校园、恋爱、奇幻等多类型海量作品,更新速度快,支持高清流畅阅读与离线缓存,界面简洁,具备智能搜索、书架管理及章节提醒功能,优化横向纵向阅读模式、夜间模式与手势翻页,提升用户沉浸体验。 漫番漫画官网直达入口地址在哪里?这是不少网友都关注…

    2026年9月25日 • 用户投稿
    600
  • 如何寻找淘宝达人帮助推广?淘宝达人申请的入口在哪里?深入了解相关的流程和入口。

    如何寻找淘宝达人帮助推广?淘宝达人申请的入口在哪里?深入了解相关的流程和入口。如何寻找淘宝达人帮助推广?淘宝达人申请的入口在哪里?深入了解相关的流程和入口。如何寻找淘宝达人帮助推广?淘宝达人申请的入口在哪里?深入了解相关的流程和入口。如何寻找淘宝达人帮助推广?淘宝达人申请的入口在哪里?深入了解相关的流程和入口。

    在淘宝这个庞大的电商生态中,淘宝达人的作用日益凸显。他们凭借庞大的粉丝基础和成熟的推广技巧,成为商家拓展市场的重要助力。然而,不少商家仍面临两大困惑:如何高效找到合适的淘宝达人进行合作?以及淘宝达人申请的具体入口究竟在哪里?就像面对一座金矿却找不到开采路径,本文将为你一一揭晓答案,助你充分利用淘宝达…

    2026年9月25日 • 用户投稿
    700
  • mysql下载好了从哪运行

    mysql下载好了从哪运行mysql下载好了从哪运行mysql下载好了从哪运行mysql下载好了从哪运行

    要运行 MySQL,请按照以下步骤操作:解压安装包运行安装向导选择自定义安装类型配置 MySQL 安装安装 MySQL启动 MySQL 服务使用客户端连接到 MySQL 如何运行 MySQL 下载 步骤 1:解压 MySQL 安装包 找到下载的 MySQL 安装包,通常是一个名为“mysql-ins…

    2026年9月25日 • 用户投稿
    100
  • win10使用Outlook查看邮件时内容显示不全?

    win10使用Outlook查看邮件时内容显示不全?win10使用Outlook查看邮件时内容显示不全?win10使用Outlook查看邮件时内容显示不全?win10使用Outlook查看邮件时内容显示不全?

    许多用户习惯使用outlook来接收和发送电子邮件,但有一部分win10系统的用户在使用outlook浏览邮件时,发现部分邮件在双击标题后弹出窗口显示内容时,后半部分内容却不见了,导致信息无法完整展示。那么,当win10系统中的outlook出现邮件内容显示不全的情况时,应该如何处理呢?接下来,请跟…

    2026年9月25日 • 用户投稿
    400
  • sublime怎么安装和使用DocBlockr插件_sublime使用DocBlockr生成注释的教程

    sublime怎么安装和使用DocBlockr插件_sublime使用DocBlockr生成注释的教程sublime怎么安装和使用DocBlockr插件_sublime使用DocBlockr生成注释的教程sublime怎么安装和使用DocBlockr插件_sublime使用DocBlockr生成注释的教程sublime怎么安装和使用DocBlockr插件_sublime使用DocBlockr生成注释的教程

    安装DocBlockr插件:通过Package Control搜索并安装DocBlockr;2. 使用方法:在函数上方输入/**后回车,自动生成含参数、返回值的注释块;3. 配置优化:可设置快捷键、自定义模板及扩展语言支持,提升注释效率。 在Sublime Text中安装和使用DocBlockr插件…

    2026年9月25日 • 用户投稿
    1100
  • 360极速浏览器收藏夹在哪个文件夹_书签数据文件本地存储路径

    360极速浏览器收藏夹在哪个文件夹_书签数据文件本地存储路径360极速浏览器收藏夹在哪个文件夹_书签数据文件本地存储路径360极速浏览器收藏夹在哪个文件夹_书签数据文件本地存储路径360极速浏览器收藏夹在哪个文件夹_书签数据文件本地存储路径

    首先定位360极速浏览器的书签文件,该文件通常存储在%LOCALAPPDATA%360ChromeChromeUser DataDefault目录下,查找名为Bookmarks和Bookmarks.bak的文件即可获取当前及备份的收藏夹数据。 如果您需要找回或备份360极速浏览器的收藏夹数据,可能需…

    2026年9月25日 • 用户投稿
    100

发表回复

登录后才能评论
关注微信