iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > PHP编程 >如何在PHP项目中实现一个队列场景
  • 513
分享到

如何在PHP项目中实现一个队列场景

2023-06-06 14:06:38 513人浏览 安东尼
摘要

本篇文章为大家展示了如何在PHP项目中实现一个队列场景,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。声明概念:资源管理器(resource manager):用来管理系统资源,是通向事务资源的途径。

本篇文章为大家展示了如何在PHP项目中实现一个队列场景,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

声明概念:

资源管理器(resource manager):用来管理系统资源,是通向事务资源的途径。数据库就是一种资源管理器。资源管理还应该具有管理事务提交或回滚的能力。
事务管理器(transaction manager):事务管理器是分布式事务的核心管理者。事务管理器与每个资源管理器(resource
manager)进行通信,协调并完成事务的处理。事务的各个分支由唯一命名进行标识。
mysql在执行分布式事务(外部XA)的时候,Mysql服务器相当于xa事务资源管理器,与mysql链接的客户端相当于事务管理器。

分布式事务原理:分段式提交
分布式事务通常采用2PC协议,全称Two Phase Commitment Protocol。该协议主要为了解决在分布式数据库场景下,所有节点间数据一致性的问题。分布式事务通过2PC协议将提交分成两个阶段:

prepare;commit/rollback

阶段一为准备(prepare)阶段。即所有的参与者准备执行事务并住需要的资源。参与者ready时,向transaction manager报告已准备就绪。
阶段二为提交阶段(commit)。当transaction manager确认所有参与者都ready后,向所有参与者发送commit命令。

事务协调者transaction manager
因为XA 事务是基于两阶段提交协议的,所以需要有一个事务协调者(transaction manager)来保证所有的事务参与者都完成了准备工作(第一阶段)。如果事务协调者(transaction manager)收到所有参与者都准备好的消息,就会通知所有的事务都可以提交了(第二阶段)。Mysql 在这个XA事务中扮演的是参与者的角色,而不是事务协调者(transaction manager)。

Mysql的XA事务分为外部XA和内部XA

外部XA用于跨多MySQL实例的分布式事务,需要应用层作为协调者,通俗的说就是比如我们在php中写代码,那么PHP书写的逻辑就是协调者。应用层负责决定提交还是回滚,崩溃时的悬挂事务。MySQL数据库外部XA可以用在分布式数据库代理层,实现对MySQL数据库的分布式事务支持,例如开源的代理工具:网易的DDB,淘宝的TDDL等等。

内部XA事务用于同一实例下跨多引擎事务,由Binlog作为协调者,比如在一个存储引擎提交时,需要将提交信息写入二进制日志,这就是一个分布式内部XA事务,只不过二进制日志的参与者是MySQL本身。Binlog作为内部XA的协调者,在binlog中出现的内部xid,在crash recover时,由binlog负责提交。(这是因为,binlog不进行prepare,只进行commit,因此在binlog中出现的内部xid,一定能够保证其在底层各存储引擎中已经完成prepare)。

mysql xa事务的语法

首先要确保mysql开启XA事务支持

SHOW VARIABLES LIKE '%xa%'

如果innodb_support_xa的值是ON就说明mysql已经开启对XA事务的支持了。 如果不是就执行:

SET innodb_support_xa = ON

主要有:

XA START 'any_unique_id'; // 'any_unique_id' 是用户给的,全局唯一在一台mysql中开启一个XA事务XA END 'any_unique_id '; //标识XA事务的操作结束XA PREPARE 'any_unique_id'; //告知mysql 准备提交这个xa事务XA COMMIT 'any_unique_id'; //告知mysql提交这个xa事务XA ROLLBACK 'any_unique_id'; //告知mysql回滚这个xa事务XA RECOVER;//查看本机mysql目前有哪些xa事务处于prepare状态

XA事务恢复
如果执行分布式事务的mysql crash了,mysql 按照如下逻辑进行恢复:
a. 如果这个xa事务commit了,那么什么也不用做
b. 如果这个xa事务还没有prepare,那么直接回滚它
c. 如果这个xa事务prepare了,还没commit, 那么把它恢复到prepare的状态,由用户去决定commit或rollback
当mysql crash后重新启动之后,执行“XA RECOVER;”查看当前处于prepare状态的xa事务,然后commit或rollback它们。

使用限制
a. XA事务和本地事务以及锁表操作是互斥的
开启了xa事务就无法使用本地事务和锁表操作

mysql> xa start 't1xa';Query OK, 0 rows affected (0.04 sec)mysql> begin;ERROR 1399 (XAE07): XAER_RMFaiL: The command cannot be executed when global transaction is in the ACTIVE statemysql> lock table t1 read;ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state

开启了本地事务就无法使用xa事务

mysql> begin;Query OK, 0 rows affected (0.00 sec)mysql> xa start 'rrrr';ERROR 1400 (XAE09): XAER_OUTSIDE: Some work is done outside global transaction

b. xa start 之后必须xa end, 否则不能执行xa commitxa rollback

所以如果在执行xa事务过程中有语句出错了,你也需要先xa end一下,然后才能xarollback

注意事项

a. mysql只是提供了xa事务的接口,分布式事务中的mysql实例之间是互相独立的不感知的。 所以用户必须自己实现分布式事务的调度器
b. xa事务有一些使用上的bug, 参考Http://www.mysqlops.com/2012/02/24/mysql-xa-optimize.html
主要是
“MySQL数据库的主备数据库的同步,通过Binlog的复制完成。而Binlog是MySQL数据库内部XA事务的协调者,并且MySQL数据库为binlog做了优化——binlog不写prepare日志,只写commit日志。
所有的参与节点prepare完成,在进行xa commit前crash。crash recover如果选择commit此事务。由于binlog在prepare阶段未写,因此主库中看来,此分布式事务最终提交了,但是此事务的操作并未 写到binlog中,因此也就未能成功复制到备库,从而导致主备库数据不一致的情况出现。
而crash recover如果选rollback, 那么就会出现全局不一致(该分布式事务对应的节点,部分已经提交,无法回滚,而部分节点回滚。最终导致同一分布式事务,在各参与节点,最终状态不一致)”

参考的那篇blog中给出的办法是修改mysql代码,这个无法在DBScale中使用。 所以可选的替代方案是不使用
主从复制进行备份,而是直接使用xa事务实现同步写来作为备份。

php+mysql实现分布式事务案例

保证数据表是innodb的

//db_finance库下CREATE TABLE `t_user_account` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id', `username` varchar(255) NOT NULL DEFAULT '' COMMENT '用户名', `money` int(11) NOT NULL DEFAULT '0' COMMENT '账户金额', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
//db_order库下CREATE TABLE `t_user_orders` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', `username` varchar(255) NOT NULL DEFAULT '', `money` int(11) NOT NULL DEFAULT '0' COMMENT '订单扣款金额', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8;

php代码

$username = '公众号PHP开源社区';$order_money = 100;$addOrder_success = addOrder($username,$order_money);$upAccount_success = updateAccount($username,$order_money);if($addOrder_success['state'] =="yes" && $upAccount_success['state']=="yes"){  commitdb($addOrder_success['xa']);  commitdb1($upAccount_success['xa']);}else{  rollbackdb($addOrder_success['xa']);  rollbackdb1($upAccount_success['xa']);}die;function addOrder ($username, $order_money){  $xa = uniqid("");  $sql_xa = "XA START '$xa'";  $db = Yii::app()->dborder_readonly;  $db->createCommand($sql_xa)->execute();  $insert_sql = "INSERT INTO t_user_orders (`username`,`money`) VALUES ($username,$order_money)";  $id = $db->createCommand($insert_sql)->execute();  $db->createCommand("XA END '$xa'")->execute();  if ($id) {    $db->createCommand("XA PREPARE '$xa'")->execute();    return ['state' => 'yes', 'xa' => $xa];  }else {    return ['state' => 'no', 'xa' => $xa];  }}function updateAccount($username, $order_money){  $xa = uniqid("");  $sql_xa = "XA START '$xa'";  $db = Yii::app()->db_finance;  $db->createCommand($sql_xa)->execute();  $sql = "update t_user_account set money=money-".$order_money." where username='$username'";  $id = $db->createCommand($sql)->execute();  $db->createCommand("XA END '$xa'")->execute();  if ($id) {    $db->createCommand("XA PREPARE '$xa'")->execute();    return ['state' => 'yes', 'xa' => $xa];  }else {    return ['state' => 'no', 'xa' => $xa];  }}//提交事务!function commitdb($xa){  $db = Yii::app()->dborder_readonly;  return $db->createCommand("XA COMMIT '$xa'")->execute();}//回滚事务function rollbackdb($xa){  $db = Yii::app()->dborder_readonly;  return $db->createCommand("XA COMMIT '$xa'")->execute();}//提交事务!function commitdb1($xa){  $db = Yii::app()->db_finance;  return $db->createCommand("XA COMMIT '$xa'")->execute();}//回滚事务function rollbackdb1($xa){  $db = Yii::app()->db_finance;  return $db->createCommand("XA ROLLBACK '$xa'")->execute();

上述内容就是如何在PHP项目中实现一个队列场景,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注编程网PHP编程频道。

--结束END--

本文标题: 如何在PHP项目中实现一个队列场景

本文链接: https://www.lsjlt.com/news/247350.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何在PHP项目中实现一个队列场景
    本篇文章为大家展示了如何在PHP项目中实现一个队列场景,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。声明概念:资源管理器(resource manager):用来管理系统资源,是通向事务资源的途径。...
    99+
    2023-06-06
  • 在java项目如何实现栈与队列
    在java项目如何实现栈与队列?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。在java中要实现栈和队列,需要用到java集合的相关知识,特别是Stack、LinkedLis...
    99+
    2023-05-31
    java 队列
  • 队列的死信队列和延迟队列在PHP与MySQL中的应用场景
    引言随着互联网应用变得越来越复杂,处理大量消息和任务的需求日益增长。队列作为一种解决方案,能够有效地实现任务的异步处理,提高系统的可伸缩性和稳定性。在队列的应用中,常见的两个概念是死信队列和延迟队列。本文将介绍这两个概念在PHP与MySQL...
    99+
    2023-10-21
    队列 (Queue) 死信队列 (Dead Letter Queue) 延迟队列 (Delay Queue)
  • 在Java项目中如何实现一个可变参数列表
    这篇文章给大家介绍在Java项目中如何实现一个可变参数列表,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Java可变参数列表详解1、接受的传入参数情况:如public void test(String ...args)...
    99+
    2023-05-31
    jav 可变参数 列表
  • 如何在PHP中实现消息队列?
    随着互联网应用和系统架构的复杂化,消息队列技术越来越被广泛应用。消息队列是一种异步处理消息的机制,常用于系统解耦、流量削峰、任务排队等场景。在PHP应用中,也可以使用消息队列来提高应用的可靠性、可扩展性、可维护性等方面的性能。本文将介绍如何...
    99+
    2023-05-14
    PHP 实现 消息队列
  • 如何实现一个延迟队列
    本篇内容介绍了“如何实现一个延迟队列”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!延迟队列定义首先,队列这...
    99+
    2024-04-02
  • 怎么用php实现一个队列
    PHP中可以使用数组来实现一个队列。下面是一个简单的PHP队列的实现示例:```phpclass Queue {private $q...
    99+
    2023-09-06
    php
  • 如何在PHP项目中实现一个反序列化字符串逃逸功能
    这篇文章给大家介绍如何在PHP项目中实现一个反序列化字符串逃逸功能,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。任何具有一定结构的数据,如果经过了某些处理而把结构体本身的结构给打乱了,则有可能会产生漏洞。0CTF 20...
    99+
    2023-06-06
  • 队列的作用和在PHP与MySQL中的应用场景
    队列是计算机科学中非常重要的一种数据结构,它可以帮助我们实现任务的异步处理和解耦。队列的基本原则是“先进先出”,即先放入队列的任务会被先取出来处理。队列的作用:异步处理:当一个任务需要耗费很长时间来完成时,可以把任务放入队列,然后让程序继续...
    99+
    2023-10-21
    PHP 队列 MySQL。
  • 如何在c#项目中实现一个winform主题
    如何在c#项目中实现一个winform主题?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。一个接口,需要做主题的控件、窗体都要实现这个接口/// <summa...
    99+
    2023-06-06
  • 如何在C++项目中实现一个aligned_malloc方法
    这篇文章将为大家详细讲解有关如何在C++项目中实现一个aligned_malloc方法,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。malloc的默认行为int main(){&n...
    99+
    2023-06-07
  • 如何在JavaScript中实现队列
    这篇文章将为大家详细讲解有关如何在JavaScript中实现队列,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1. 队列数据结构队列是一种“先入先出”(FIFO)数据结构...
    99+
    2024-04-02
  • 在Java项目中如何实现一个同步锁
    在Java项目中如何实现一个同步锁?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。Java 同步锁(synchronized)详解及实例Java中cpu分给每个线程的时间片是...
    99+
    2023-05-31
    java 同步锁 ava
  • JavaScript中怎么实现一个队列
    JavaScript中怎么实现一个队列,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。1.  队列数据结构如果你喜欢四处旅行,肯定在火...
    99+
    2024-04-02
  • 如何在C++项目中实现一个取余运算
    如何在C++项目中实现一个取余运算?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、C++中的整数除法C++中整数除法和取余用的是truncate除法(舍0取整),而给无符号类...
    99+
    2023-06-06
  • 如何在Java项目中实现一个命令模式
    如何在Java项目中实现一个命令模式?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。定义:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排...
    99+
    2023-05-31
    java ava 命令模式
  • 在java项目中如何实现一个单例模式
    在java项目中如何实现一个单例模式?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。java设计模式--单例模式 单例设计模式Singleton是一种创...
    99+
    2023-05-31
    java 单例模式 ava
  • SpringBoot2如何整合Redis哨兵集群 实现消息队列场景
    这篇文章主要介绍了SpringBoot2如何整合Redis哨兵集群 实现消息队列场景,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、Redis集群简介1、RedisClus...
    99+
    2023-06-02
  • 如何在java项目中实现一个高并发锁
    如何在java项目中实现一个高并发锁?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。乐观锁乐观锁适合这样的场景:读不会冲突,写会冲突。同时读的频率远大于写。以下面的代码为例,悲观...
    99+
    2023-05-31
    java 高并发锁 ava
  • C语言如何实现一个链表队列
    本篇内容主要讲解“C语言如何实现一个链表队列”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C语言如何实现一个链表队列”吧!C语言数据结构链表队列的实现1.写在前面  队列是一种和栈相反的,遵循先...
    99+
    2023-06-16
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作