如何防止这种争用情况发生?我知道Laravel中的事务阻塞更新,但如何防止使用过时数据?是否有方法在另一个事务进行时锁定数据库以防止读取?(即,让第二个请求等待第一个请求完成?)
- 假设数据库中主键id = 7的用户名字段为空。**
请求1进入并执行以下操作:
public function raceCondition1() {
DB::beginTransaction();
//Get the model with primary key 7
$user = User::findorfail(7);
sleep(6);
$user->username = 'MyUsername';
$user->save();
DB::commit();
}
- 两**秒后,我运行Request 2,它只是将一些内容连接到username列并保存:
public function raceCondition2() {
DB::beginTransaction();
$user = User::findorfail(7);
sleep(6);
$user->username = 'USER_' . $user->username;
$user->save();
DB::commit();
}
在这种情况下,数据库中的结果为:用户_
第二个请求在第一个请求可以保存之前从数据库中读取,并使用了过时的NULL值。是否有方法在另一个事务正在进行时锁定数据库以防止读取?(即,让第二个请求等待第一个请求完成?)
5条答案
按热度按时间yqlxgs2m1#
Laravel支持“悲观锁定”。有关这方面的更多信息,请参考Laravel关于悲观锁定的文档。
xzlaal3s2#
当您正在执行查询并且希望拥有一种机制,以便在查询执行过程中可能出错的情况下撤消所产生的修改时,可以使用事务。
正如您正在寻找的是内部锁定方法,其中对数据库的每个请求都放在队列中,只有在处理前一个请求时才进行处理。
我不知道这个特性是否来自laravel ORM,但它可以很容易地从经典的sql查询中实现。
查看这个链接,了解整个机制是如何工作的,我相信您正在寻找的是行级锁定。
Locking Methods
5tmbdcev3#
为了解决应用程序的竞争条件问题,需要高性能,乐观锁优于悲观锁,因为悲观锁可能会产生死锁。
实际上,乐观锁不是数据库的特性,它只是一种最佳实践。
要了解更多详细信息,您可以查看这个伟大的答案:Optimistic locking in MySQL
enxuqcxy4#
我在做什么因为我得到了一大堆错误
production.ERROR:数据库状态[23000]:完整性约束冲突:1062重复输入
这是基于使用队列的多线程表插入...我认为在Laravel firstOrCreate中这样做是可以的,然后我尝试了updateOrCreate,我必须说这是一个巨大的疏忽,考虑到所有东西都是多线程多人使用的...等等...这对我来说很简单。至少到目前为止它看起来是有效的
现在,如果竞态条件很活泼,有多个冲突,这仍然会失败,但可以通过使函数循环冗余,或只是使它冗余几次来进行某种对冲...看起来很糟糕,但我没有遇到更多的冲突...
hrirmatl5#
对于数字,可以使用increment()、decrement()方法。
示例:
$transaction->increment('amount', $amount);
我用简单的代码测试了这个。
要测试这个,打开两个不同的终端和tinker,创建一个id =〉1和amount =〉5000的记录。
运行
在一个端子中,在另一个端子的下方
通过运行
Transaction::all();
进行检查