reshadman/laravel-optimistic-locking

为Eloquent模型添加乐观锁功能。

1.1.0 2019-01-11 19:01 UTC

This package is auto-updated.

Last update: 2024-09-22 08:58:03 UTC


README

Build Status

为Eloquent模型添加乐观锁功能。

安装

composer require reshadman/laravel-optimistic-locking

此包支持Laravel 5.5., 5.6., 5.7., 5.8. 和 6.*。

使用方法

基本使用

在您的模型中使用 \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';
    }
}

什么是乐观锁?

有关详细说明,请阅读 《企业应用架构模式》 中的并发部分。

有两种方法可以处理通用的并发竞争条件

  1. 不允许其他进程(或用户)读取和更新相同的资源(悲观锁)
  2. 允许其他进程并发读取相同的资源,但如果其中一个进程在其他人之前更新了资源,则不允许进一步更新(乐观锁)。

Laravel允许使用文档中描述的悲观锁,此包允许您以类似Rails的方式使用乐观锁。

乐观锁期间会发生什么?

每次您对资源(模型)执行upsert操作时,表中的 lock_version 计数字段都会增加 1,如果您读取了资源,而另一个进程在您读取后更新了资源,则实际版本计数会增加,如果当前进程尝试更新模型,则简单地抛出 StaleModelLockingException,您应该根据您的业务逻辑处理竞争条件(合并、重试、忽略)。这很简单,只需通过向 乐观锁可用的模型 的更新查询添加以下条件即可

<?php
$query->where('id', $this->id)
    ->where('lock_version', $this->lock_version)
    ->update($changes);

如果资源在您的更新尝试之前已被更新,则上述操作将简单地更新 记录,这意味着模型在当前尝试之前已被更新或已被删除。

为什么我们不使用 updated_at 来跟踪更改?

因为它们可能在两个并发更新期间保持不变。

运行测试

克隆仓库,执行 composer 安装并运行

vendor/bin/phpunit

许可协议

MIT 许可协议(MIT)。请参阅 许可文件 获取更多信息。