Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/229.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 两个事务同时进行,数据重复_Php_Mysql_Database_Laravel_Transactions - Fatal编程技术网

Php 两个事务同时进行,数据重复

Php 两个事务同时进行,数据重复,php,mysql,database,laravel,transactions,Php,Mysql,Database,Laravel,Transactions,我有一个API,它同时接收两个请求。它还导致两个事务同时运行,从而复制数据。我的端点的伪代码是: public function myEndpoint(Request $request) { $newOrderID = $request->get('order_id'); DB::beginTransaction(); try { $ordersCount = Order::where(['id' => $newOrderID])->count();

我有一个API,它同时接收两个请求。它还导致两个事务同时运行,从而复制数据。我的端点的伪代码是:

public function myEndpoint(Request $request)
{
  $newOrderID = $request->get('order_id');

  DB::beginTransaction();

  try {
    $ordersCount = Order::where(['id' => $newOrderID])->count();
    if ($ordersCount === 0) {
      Order::create(['id' => $newOrderID]);
      
      $stat = Stat::where(['date' => Carbon::now()])->first();
      $stat->orders_count = $stat->orders_count + 1;
      $stat->save();
    }

    DB::commit();
  } catch (Exception $e) {
    DB::rollBack();
  }
}
因此,端点是一个事务,它:

  • 将新订单ID保存到表中
  • 增量统计
orders表没有唯一键。它检查重复项,如果已经有订单ID,则不应执行任何操作

问题是-两个事务同时运行,还没有重复,并且数据被重复,因此我最终有两行具有相同的订单ID

设置唯一键将不起作用,因为统计表始终会错误地递增


这个问题有好的解决方案吗?

您可以使用mysql触发器来解决重复条目。这是示例触发器。您不必检查php代码中是否存在

DROP TRIGGER IF EXISTS order_transaction_before_insert;
DELIMITER $$

CREATE  TRIGGER order_transaction_before_insert
BEFORE INSERT ON order FOR EACH ROW
BEGIN

    DECLARE msg varchar(128);
    DECLARE foundCount INT;


    SET foundCount = (
        SELECT COUNT(*)
        FROM order
        WHERE
              order_id = NEW.order_id
    );

    IF( foundCount > 0) THEN
        SET msg = CONCAT('DuplicateEntryError: Trying to insert a duplicate value in order table for driver: ', NEW.order_id);
        SIGNAL SQLSTATE VALUE '45000' SET MESSAGE_TEXT =  msg;
    END IF;

END; $$

DELIMITER ;

您可以使用mysql触发器来解析重复条目。这是示例触发器。您不必检查php代码中是否存在

DROP TRIGGER IF EXISTS order_transaction_before_insert;
DELIMITER $$

CREATE  TRIGGER order_transaction_before_insert
BEFORE INSERT ON order FOR EACH ROW
BEGIN

    DECLARE msg varchar(128);
    DECLARE foundCount INT;


    SET foundCount = (
        SELECT COUNT(*)
        FROM order
        WHERE
              order_id = NEW.order_id
    );

    IF( foundCount > 0) THEN
        SET msg = CONCAT('DuplicateEntryError: Trying to insert a duplicate value in order table for driver: ', NEW.order_id);
        SIGNAL SQLSTATE VALUE '45000' SET MESSAGE_TEXT =  msg;
    END IF;

END; $$

DELIMITER ;

如果已经在处理相同的订单id,则可以进行散列并锁定传入请求

  • 胡闹
  • 当请求传入时,检查订单id是否在哈希中
  • 如果已在哈希中,则返回重复请求
  • 检查订单id是否在DB中
  • 如果不存在,则插入数据库
  • 从散列中清除订单id

  • 如果已经在处理相同的订单id,则可以进行散列并锁定传入请求

  • 胡闹
  • 当请求传入时,检查订单id是否在哈希中
  • 如果已在哈希中,则返回重复请求
  • 检查订单id是否在DB中
  • 如果不存在,则插入数据库
  • 从散列中清除订单id

  • 假设您的订单ID只是某个任意(唯一)的自动增量值,它无论如何都不能用于检测重复项。两个传入插入之间还存在哪些其他信息可能会提示我们其中一个/两个都是重复的?为了回答这个问题,我们需要知道这一点。order ID是一个生成的ID,作为查询参数传递给端点,如
    https://example.com/api/my-endpoint?order_id=n1992bb3j1bbb3
    。使用相同的订单ID多次并行发送此请求有时会导致我解释的情况。您能告诉我们有关此“统计”表的信息吗?“统计”表保存了“订单”表中插入的数量。如果查询不会更新“orders”表中重复键上的“statistics”表,那么唯一索引将是完美的。但这真的不可能,是吗?例如,在重复键插入“订单”时,查询不会在那里插入冗余数据,但仍会更新“统计”表中的计数器。使用
    lockForUpdate
    检查重复的订单ID如何,以便其他事务需要等待?假设您的订单ID只是任意的(唯一的)自动递增值,无论如何不能用于检测重复项。两个传入插入之间还存在哪些其他信息可能会提示我们其中一个/两个都是重复的?为了回答这个问题,我们需要知道这一点。order ID是一个生成的ID,作为查询参数传递给端点,如
    https://example.com/api/my-endpoint?order_id=n1992bb3j1bbb3
    。使用相同的订单ID多次并行发送此请求有时会导致我解释的情况。您能告诉我们有关此“统计”表的信息吗?“统计”表保存了“订单”表中插入的数量。如果查询不会更新“orders”表中重复键上的“statistics”表,那么唯一索引将是完美的。但这真的不可能,是吗?例如,在重复键插入到“订单”时,查询不会在那里插入冗余数据,但仍会更新“统计”表中的计数器。在检查重复订单ID时使用
    lockForUpdate
    如何,以便其他事务需要等待?