kerwin-cn / laravel-optimistic-locking
为Eloquent模型添加乐观锁功能。
Requires
- php: ^7.1|^8.0
- illuminate/database: ~5.5.0|~5.6.0|~5.7.0|~5.8.0|^6.0|^7.5|^8.0|^9.0
- illuminate/support: ~5.5.0|~5.6.0|~5.7.0|~5.8.0|^6.0|^7.5|^8.0|^9.0
Requires (Dev)
- ext-pdo_sqlite: *
- mockery/mockery: ^1.0.0
- orchestra/testbench: ~3.5.0|~3.6.0|~3.8.0|^4.0|^5.0
- phpunit/phpunit: ^7.0|^8.0|^9.0
README
为Eloquent模型添加乐观锁功能。
安装
composer require kerwin-cn/laravel-optimistic-locking
此包支持Laravel 5.5., 5.6., 5.7., 5.8., 6., 7. 和 8.*。
用法
基本用法
在模型中使用 \Reshadman\OptimisticLocking\OptimisticLocking
特性
<?php class BlogPost extends Model { use OptimisticLocking; }
并将整数 lock_version
字段添加到模型的表中
<?php $schema->integer('lock_version')->unsigned()->nullable();
然后您就可以开始了,如果两个不同的进程 并发 地编辑相同的资源,则会抛出以下异常
<?php \Reshadman\OptimisticLocking\StaleModelLockingException::class;
您应该捕获上述异常并根据您的业务逻辑采取适当的行动。
在业务事务中维护lock_version
您可以在业务事务中通过通知您的API或HTML客户端当前版本来跟踪锁版本
<input type="hidden" name="lock_version" value="{{$blogPost->lock_version}}"
在控制器中
<?php // Explicitly setting the lock version class PostController { public function update($id) { $post = Post::findOrFail($id); $post->lock_version = request('lock_version'); $post->save(); // You can also define more implicit reusable methods in your model like Model::saveWithVersion(...$args); // or just override the default Model::save(...$args); method which accepts $options // Then automatically read the lock version from Request and set into the model. } }
因此,如果两个作者同时编辑相同的内容,您可以跟踪您的 读取状态,并要求第二个作者重新编写他的更改。
禁用和启用乐观锁
您可以为特定实例禁用和启用乐观锁
<?php $blogPost->disableLocking(); $blogPost->enableLocking();
默认情况下,当您在模型中使用 OptimisticLocking
特性时,乐观锁是启用的,要更改默认行为,可以将锁定严格设置为 false
<?php class BlogPost extends \Illuminate\Database\Eloquent\Model { use \Reshadman\OptimisticLocking\OptimisticLocking; protected $lock = false; }
然后您可以启用它: $blogPost->enableLocking();
使用不同的列来跟踪版本
默认情况下使用 lock_version
列来跟踪版本,您可以通过覆盖特性以下方法来更改这一点
<?php class BlogPost extends \Illuminate\Database\Eloquent\Model { use \Reshadman\OptimisticLocking\OptimisticLocking; /** * Name of the lock version column. * * @return string */ protected static function lockVersionColumn() { return 'track_version'; } }
什么是乐观锁?
有关详细说明,请阅读《企业应用架构模式》中关于并发的部分。
有两种方法可以处理通用的并发竞态条件
- 不允许其他进程(或用户)读取和更新相同的资源(悲观锁)
- 允许其他进程并发读取相同的资源,但如果其中一个进程在其他人之前更新了资源,则不允许进一步更新(乐观锁)。
Laravel允许使用文档中描述的悲观锁,此包允许您以类似Rails的方式实现乐观锁。
乐观锁期间会发生什么?
每次您对资源(模型)执行upsert操作时,表中的 lock_version
计数器字段将增加 1
,如果您读取资源,另一个进程在您读取后更新了资源,则实际版本计数器将增加一个,如果当前进程尝试更新模型,则会抛出 StaleModelLockingException
异常,并且您应该根据您的业务逻辑处理竞态条件(合并、重试、忽略)。这很简单,只需将以下标准添加到 乐观锁模型 的更新查询中即可
<?php $query->where('id', $this->id) ->where('lock_version', $this->lock_version) ->update($changes);
如果资源在您的更新尝试之前已被更新,则上述操作将简单地更新 无 记录,这意味着模型在当前尝试之前已被更新或已被删除。
为什么我们不使用 updated_at
来跟踪更改?
因为在两次并发更新期间,它们可能保持不变。
运行测试
克隆仓库,执行composer install并运行
vendor/bin/phpunit
许可协议
MIT 许可协议 (MIT)。请参阅许可文件获取更多信息。