Php 如何在laravel中处理同步保存API请求?

Php 如何在laravel中处理同步保存API请求?,php,database,laravel,api,concurrency,Php,Database,Laravel,Api,Concurrency,我正试图通过API保存新预订。下面是保存预订功能的示例代码 public function save_booking(Request $request){ $booking = new Booking; $booking->booking_number = generate_booking_id(); $booking->booking_type = $request->input(

我正试图通过API保存新预订。下面是保存预订功能的示例代码

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();
}
注意-generate_booking_id()是一个帮助函数,用于生成类似于BN-202105-0001的预订(最后四位数字0001通过将预订表中的总记录计数+1相加计算)

当两个或多个同时的save API请求试图保存新预订时,将为两个请求分配相同的预订编号。(例如,请求1=BN-202105-0001,请求2=BN-202105-0001等等。)

我想为每个同时的API请求分配不同的预订编号。(例如,对于请求1=BN-202105-0001、请求2=BN-202105-0002、请求3=BN-202105-0003、请求4=BN-202105-0004,有4个同时请求试图保存新预订)

如何在Laravel中解决这个并发请求问题


提前谢谢

发生这种情况是因为您的
generate\u booking\u id()
正在从两个不同的请求中同时读取数据库,并为您生成预订id

您可以通过在db级别创建插入时的
触发器来避免这种情况,如下所示,为您更新
预订号码
,而不是手动执行。触发器将确保在创建预订后而不是之前自动更新
预订号

假设您使用的是MySQL:(不过,您可以在其他数据库管理系统中使用相同的方法)

替代解决方案可以是先将预订记录插入数据库,然后调用
生成预订id()
函数正确计算预订编号,然后将记录更新到数据库中:

 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();
            
    }

为了简单起见,您可以尝试将预订号码设置为模型的属性。然后,此属性将给定前缀与预订的实际id组合。这样,您就不需要创建自己的增量函数,只需组装您已经得到的函数

物业示例:

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]));
   }
}
函数getBookingNumberAttribute作为属性的函数:
booking\u 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);
您应该始终获得一个新ID,因为创建唯一ID的逻辑由mysql数据库处理


我还添加了一个方法来显示如何通过预订编号查找预订。

为了确保我正确理解您的问题:您有自己的增量函数,但有时它会生成一个重复的键,所以你最终得到了重复的预订号码?@RobBiermann实际上我的函数生成了正确的预订号码,但当两个请求同时保存记录时,两个请求分配了相同的预订号码。好吧,那么这是一个典型的并发问题。我首先将数据库中的booking_number字段设置为唯一,这样就不可能存储重复项。然后,当由于重复而无法保存时,只需增加数字和retry@RobBiermann谢谢你的建议。我还添加了一个更详细的答案,这在我看来是最理想的。使用这种方法,您不需要进行错误处理,这可能是一件痛苦的事情。我认为您应该尝试一下触发器,在这种情况下,您不必修改代码。
$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);