简体   繁体   English

如何处理 laravel 中的同时保存 API 请求?

[英]How to handle simultaneous save API requests in laravel?

I am trying to save new booking through API.我正在尝试通过 API 保存新预订。 Below is the sample code of save booking function.以下是保存预订 function 的示例代码。

public function save_booking(Request $request){
        $booking = new Booking;
        $booking->booking_number            = generate_booking_id();
        $booking->booking_type              = $request->input('bookingType');
        $booking->booking_date              = $request->input('bookingDate');
        $booking->booking_time              = $request->input('bookingTime');
        $booking->booking_status            = $request->input('bookingStatus');
        $booking->save();
}

Note - generate_booking_id() is a helper function to generate booking like BN-202105-0001 (Last four digits 0001 are calculated by adding total records count + 1 from booking table).注意 - generate_booking_id() 是一个帮助器 function 来生成像 BN-202105-0001 这样的预订(最后四位数字 0001 是通过从预订表中添加总记录数 + 1 来计算的)。

When two or more simultaneous save API requests trying to save new booking, same booking number is assigned to both requests.当两个或多个同时保存 API 请求尝试保存新预订时,将为两个请求分配相同的预订号。 (Eg Request 1 = BN-202105-0001, Request 2 = BN-202105-0001 and so on.) (例如请求 1 = BN-202105-0001,请求 2 = BN-202105-0001 等等。)

I want to assign different booking number to each of simultaneous API request.我想为每个同时的 API 请求分配不同的预订号。 (Eg There are 4 simultaneous request trying to save new booking then for Request 1 = BN-202105-0001, Request 2 = BN-202105-0002, Request 3 = BN-202105-0003, Request 4 = BN-202105-0004) (例如,有 4 个同时请求尝试保存新预订,然后请求 1 = BN-202105-0001、请求 2 = BN-202105-0002、请求 3 = BN-202105-0003、请求 4 = BN-202105-0004)

How do I solve this concurrent request problem in Laravel?如何解决 Laravel 中的这个并发请求问题?

Thanks in advance!提前致谢!

This is happening because your generate_booking_id() is reading the db simultaneously from two different requests and generating the booking id for you.发生这种情况是因为您的generate_booking_id()正在同时从两个不同的请求中读取数据库并为您生成预订 ID。

You can avoid this, by creating a ON INSERT trigger at the db level like the following to the update the booking_number for you instead of you manually doing it.您可以避免这种情况,方法是在数据库级别创建一个ON INSERT触发器,如下所示,为您更新booking_number ,而不是手动执行。 The trigger will make sure to automatically update the booking_number after the booking has been created and not before it.触发器将确保在创建预订之后而不是之前自动更新booking_number

Assuming you are using MySQL: (Nevertheless, you could use the same approach in other database management systems)假设您使用的是 MySQL:(尽管如此,您可以在其他数据库管理系统中使用相同的方法)

CREATE TRIGGER 'bookings'.'update_booking_number'
AFTER INSERT ON 'bookings' FOR EACH ROW
BEGIN
    UPDATE bookings b
      SET booking_number = (SELECT CONCAT('BN-202105-000',COUNT(*) + 1) FROM bookings) 
      WHERE b.id = NEW.id;
END;

Alternate solution could be to insert the booking record first into the db and then call the generate_booking_id() function to calculate the booking_number correctly and then update the record into the db:另一种解决方案是先将预订记录插入数据库,然后调用generate_booking_id() function 以正确计算预订号码,然后将记录更新到数据库中:

 public function save_booking(Request $request){
            $booking = new Booking;
            $booking->booking_type              = $request->input('bookingType');
            $booking->booking_date              = $request->input('bookingDate');
            $booking->booking_time              = $request->input('bookingTime');
            $booking->booking_status            = $request->input('bookingStatus');
            $booking->save();

            $booking->booking_number            = generate_booking_id();
            $booking->save();
            
    }

For the sake of simplicity, you could try making the booking_number a property of your model.为简单起见,您可以尝试将 booking_number 设为 model 的属性。 This property then combines a given prefix with the actual id of the booking.然后,此属性将给定前缀与预订的实际 id 结合起来。 That way you do not need to create your own incremental function, and just assemble what you already got.这样您就不需要创建自己的增量 function,只需组装您已有的。

Example of the property:属性示例:

namespace App\Models;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Booking extends Model
{
    use HasFactory;

    function getBookingNumberAttribute() {
        $date = Carbon::createFromFormat('Y-m-d', $this->attributes['booking_date']);
        $year = $date->year;
        $month = $date->format('m');
        $fourDigitId = sprintf('%04d', $this->attributes['id']);
        return "BN$year$month-$fourDigitId";
   }

    static function findByBookingNumber($booking_number) {
        $splitBookingNumber = explode('-', $booking_number);
        return self::where('id', intval($splitBookingNumber[1]));
   }
}

The function getBookingNumberAttribute functions as an accessor for the property: booking_number , so when you run: function getBookingNumberAttribute 用作属性的访问器booking_number ,因此当您运行时:

$now = Carbon::now();
$booking = Booking::create([
    'booking_date' => $now->format('Y-m-d'),
    'booking_time' => $now->format('H:i:s'),
    'booking_status' => 'new',
]);
dump($booking->booking_number);

You should always get a new ID, as the logic for creating the unique id is handled by the mysql database.您应该始终获得一个新 ID,因为创建唯一 ID 的逻辑由 mysql 数据库处理。

I've also added a method to show how to find a booking by its booking number.我还添加了一种方法来显示如何通过预订编号查找预订。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM