Php 如何在laravel中处理同步保存API请求?
我正试图通过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(
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);