在Laravel中有任何方法可以阻止同时与同一记录进行交互。例如,如果用户A正在编辑记录,那么我需要同时阻止用户B编辑同一记录。
注意:我正在使用SESSION_DRIVER = file& Laravel 5.2
目前有大约500多名用户使用该系统,它是一种管理员面板,管理员与记录交互,但我需要停止并发访问。什么是最佳解决方案。
答案 0 :(得分:3)
我最近实施了类似的东西。
对于每个相关的表,添加一个名为“lock”的列,类型为“dateTime”,如下所示:
$table->dateTime('lock')->nullable();
现在转到控制器并找到“编辑”方法。在这里你必须检查是否设置了'lock'。如果是,你必须检查它是否比15分钟更早(这很重要,因为如果用户退出页面而不更新记录,它将永久锁定)。这可以这样编码:
$sample = $this->sampleRepository->getById($idsample);
if (!$sample->lock || (strtotime($sample->lock) < strtotime('-15minutes'))) {
// Ok he can access the record
} else {
// He can not access the record
}
如果用户有权访问该记录,则必须更新“锁定”,以便其他人无法访问该记录。
if (!$sample->lock || (strtotime($sample->lock) < strtotime('-15minutes'))) {
// Ok he can access the record
$sample->lock = \Carbon\Carbon::now();
$sample->save();
// Return view, etc.
} else ...
现在让我们看看“更新”方法。更新记录后,您需要重置“锁定”,以便下一个用户可以再次编辑记录。只需添加此行并照常更新记录:
$sample->lock = null;
现在只有一个用户可以一次编辑一条记录。
您还可以创建“强制解锁”方法,用户可以使用该方法重置“锁定”而无需等待15分钟。
这是一个简单的实现。使用javascript可以更好地工作,因为如果有人正在编辑记录,你可以实时查看。
答案 1 :(得分:2)
以下是我能够实现这一目标的方法。
1)创建迁移以在模型is_editing
和editing_by
以及updated_at
中添加2列
(如果已经存在,则无需创建updated_at
)
2)制作中间件php artisan make:middleware StopConcurrentOperations
。
3)在app/Http/Kernel.php
下的$routeMiddleware
注册中间件。
4)将中间件应用于控制器
$this->middleware('concurrent.operations',["only"=>["edit","update"]]);
5)阻止中间件中的并发编辑
<?php
namespace App\Http\Middleware;
use App\OperationActivity;
use Carbon\Carbon;
use Closure;
use Illuminate\Support\Facades\Auth;
class StopConcurrentOperations
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
$operation_id = current($request->route()->parameters());
$user_id = Auth::guard('admin')->user()->id;
if(Auth::guard('admin')->user() && !empty($operation_id)){
$activity = OperationActivity::firstOrNew(["operation_id" => $operation_id]);
if($activity->is_editing && $activity->updated_at->diffInMinutes(Carbon::now())<5 && $activity->editing_by!=$user_id)
abort(409);
else {
$activity->is_editing = true;
$activity->editing_by = $user_id;
$activity->save();
}
}
return $next($request);
}
}
这里我正在检查某人是否已经编辑了记录并检查了编辑执行的时间。
6)可选择在客户端,如果编辑用户关闭窗口,则取消阻止记录,如
window.onbeforeunload = function() {
var url = "{{route('unlock_route_name',$operation->id)}}";
$.ajax({ url: url, method: 'post' })
};
要从客户端完成此过程,您必须在控制器中创建路径和方法,然后解锁记录,如
$operation = Operation::findOrFail($id);
$activity = $operation->activities()->where("is_editing",true)->first();
$activity->is_editing = false;
$activity->save();
注意:在我的示例中,我有不同的表来记录活动alerady OperationActivity
,而模型名称可能是Operation
答案 2 :(得分:1)
您需要在表和相应的模型属性中添加名为editing
的列。
检查editing
是否为false
,然后让用户进行编辑。
在任何用户编辑中,将其值更改为true,
答案 3 :(得分:1)
并发访问问题可以通过更简单但更有效的方式解决:
向表迁移中添加一个version
字段,默认值为 0 。
$table->smallInteger('version')->default(0);
version
的值将在每次成功的更新操作后递增。
version
值不等于存储记录的版本值,则更新操作将不会成功。示例-两个用户试图更新产品记录,因此他们向您的应用程序发送了 edit 请求:
version
值为 0 。version
值为 0的产品字段到您的应用程序。version
值是否等于数据库中存储的值。version
值( 0 )是否等于数据库中存储的值( 1 )。更新功能:
public function update(Request $request, $id)
{
// request validation here
$product = Product::find($id);
if ($request->version == $product->version) {
// update here
$product->version = $product->version + 1;
$product->save();
return response()->json("product updated successfully!", 200);
}
return response()->json("concurrent access: the product has been updated by another user!", 400);
}
这样,记录始终可用于更新,但是如果2个或更多用户尝试同时更新同一记录,则更新操作将失败。
答案 4 :(得分:0)
我做过类似的事情,但是当用户发送“put”时,首先检查数据是否被其他人同时更改,如果没有 - 更新,否则返回信息和新数据。
您只能检查“更新日期”,或检查所有数据。