我正在尝试实施某种调度系统。所以我有一个TimeBlock的数据库设计,每行间隔15分钟。实际的数据库将更加复杂,下表仅是说明我的情况。
可用时间表
id | date | start_time | end_time | doctor_id | status
时间限制表
id | appointment_id | available_time_id | start_time | end_time | status
可用时间例如
id | date | start_time | end_time | doctor_id | status
1 | 2018-06-18 | 08:00:00 | 09:00:00 | 1 | Active
例如TimeBlock
id | appointment_id | available_time_id | start_time | end_time | status
1 | null | 1 | 08:00:00 | 08:15:00 | Active
2 | null | 1 | 08:15:00 | 08:30:00 | Active
因此,当用户想要预订时间时,系统将基于start_time和状态以及列约会ID是否为null来检查表。如果满足条件,则应该进行更新。
当两个用户尝试同时选择同一时间时,发生我的问题。我的验证将通过,然后该用户的一个条目将覆盖另一个用户的条目。我该如何处理这个问题?我曾尝试使用laravel的悲观锁(sharedLock和lockForUpdate),但无济于事。不确定我使用的是错误的还是什么。
public function create() {
if (request()->has('member_id')) {
$member_id = request('member_id');
} else {
$member_id = get_member_id();
}
try {
DB::beginTransaction();
$member = Member::find($member_id);
$member_treatment = DB::table('Member_Treatment')->where('id', request('member_treatment_id'))->first();
$treatment = Treatment::find($member_treatment->treatment_id);
$date = Carbon::parse(request('date'));
$start_time = Carbon::parse(request('time'));
$end_time = $start_time->copy()->addMinutes($treatment->durationRequired);
$member_package_id = request('member_package_id');
$doctor = Doctor::find(request('doctor_id'));
$available_time = AvailableTime::available($doctor, $treatment, $date, $start_time)->first();
// if (!$this->validate($date, $start_time, $doctor->id)) {
// DB::rollback();
// return false;
// }
$data = [
'doctor_id' => request('doctor_id'),
'member_id' => $member_id,
'treatment_id' => $member_treatment->treatment_id,
'member_treatment_id' => $member_treatment->id,
'member_package_id' => request('member_package_id'),
'available_time_id' => $available_time->id,
'date' => $date->format('Y-m-d'),
'start_time' => $start_time->format('H:i:s'),
'end_time' => $end_time->format('H:i:s'),
'status' => Appointment::$pending,
'created_by' => Auth::id() ?: $member->user_id
];
if (request()->has('remarks'))
$data['remark'] = request('remarks');
if (request()->has('admin_remark'))
$data['admin_remark'] = request('admin_remark');
$appointment = Appointment::create($data);
$this->update_timeblocks($appointment);
$this->update_member_package($appointment, false);
DB::commit();
return $appointment;
} catch (\Exception $e){
DB::rollback();
dd($e);
}
}
protected function update_timeblocks(Appointment $appointment) {
$start_time = Carbon::parse($appointment->start_time);
// add buffer
$end_time = Carbon::parse($appointment->end_time)
->addMinutes(Appointment::$buffer);
// subtract interval to get the previous timeblock
$end_time->subMinutes(TimeBlock::$interval);
// retrieve all
$timeblocks = DB::table('TimeBlockMaster')
->where('available_time_id', $appointment->available_time_id)->get();
foreach ($timeblocks as $key => $timeblock) {
$time = Carbon::parse($timeblock->start_time);
$block_starttime = Carbon::parse($timeblock->start_time);
$block_endtime = $start_time->copy()->addMinutes($appointment->treatment->duration);
if ($time >= $start_time && $time < $end_time) {
$timeblock->appointment_id = $appointment->id;
$timeblock->end_time = $block_endtime;
$timeblock->available_duration = $block_starttime->diffInMinutes($block_endtime);
$timeblock->status = TimeBlock::$reserved;
}
if ($time == $end_time) {
$timeblock->appointment_id = $appointment->id;
$timeblock->end_time = $block_endtime;
$timeblock->available_duration = $block_starttime->diffInMinutes($block_endtime);
$timeblock->status = TimeBlock::$buffer;
}
}
$index_range = [];
$start = 0;
$end = 0;
// get the index of timeblocks that have appointment
for ($i = 0; $i < count($timeblocks); $i++) {
if (($i+1) < count($timeblocks)) {
$current = $timeblocks[$i]->appointment_id;
$next = $timeblocks[$i+1]->appointment_id;
if ($current != $next) {
$end = $i;
$index_range[] = ['start' => $start, 'end' => $end];
$start = $i+1;
}
} else {
$index_range[] = ['start' => $start, 'end' => $i];
}
}
$index = 0;
foreach ($index_range as $range) {
$endtime = Carbon::parse($timeblocks[$range['end']]->start_time)->addMinutes(TimeBlock::$interval);
$index = $range['start'];
for ($i = $index; $i <= $range['end']; $i++ ) {
$starttime = Carbon::parse($timeblocks[$i]->start_time);
DB::table('TimeBlockMaster')->where('id', $timeblocks[$i]->id)
->update([
'appointment_id' => $timeblocks[$i]->appointment_id,
'available_duration' => $starttime->diffInMinutes($endtime),
'start_time' => $timeblocks[$i]->start_time,
'end_time' => $endtime->format('H:i:s'),
'status' => $timeblocks[$i]->status
]);
}
}
}
答案 0 :(得分:0)
我会尝试添加类似的内容来“保留”约会
$date = Carbon::parse(request('date'));
$start_time = Carbon::parse(request('time'));
$available_time = AvailableTime::join('time_block', 'available_time.id', '=', 'time_block.available_time_id')
->where('available_time.date', $date)
->where('time_block.start_time', $start_time)
->where('available_time.doctor_id', request('doctor_id') )
->value('time_block.id');
if (empty($available_time) || blank($available_time) ) {
return false; // Add your return
}
$time_block= TimeBlock::find($available_time);
$time_block->update([
'appointment_id' => 0
]);
如果您将其添加到开始(在需要的地方更改),则应解决大多数问题,因为这将有效地保留第一人保留的时间,并减少您可以让另一个人预定相同约会时间的时间