在 Laravel 7 中使用 UUID
最近我不得不在 Laravel 7 实现 通用唯一识别码 ( UUIDs ),并遇到一些问题。我希望这帖子可为其他正在做相同事情的人解惑。
使用 UUIDs 的高级理由
A) 它们从你的 统一资源定位符 移除编号的 身份识别号 ,故用户不能看到你的应用已创建多少确定的对象。例如:
https://myapp.com/api/users/5
对比:
https://myapp.com/api/users/0892b118-856e-4a15-af0c-66a3a4a28eed
B) 它们让 身份识别号 远难于猜测。这有益于安全性,但我们可能应当实现其他技术以防范之。
作为主键实现 UUIDs
如何改变数据库迁移
首先,在数据库迁移中,你要将当前自动递增的 ID
字段替换为 UUIDs
。你还可以遵循以下方法:保留自动递增 ID
并将 UUID
作为表中的附加字段,在用户展示 URL
时使用 (在这种情况下,你将 ID
隐藏到模型中),但这不是我们能在这里做的。 让我们看看假设的 employees
表是什么样子的。
public function up()
{
Schema::create('employees', function (Blueprint $table) {
$table->uuid('id')->primary;
$table->string('name');
$table->string('email')->unique();
$table->string('work_location')->nullable();
$table->timestamps();
});
}
在这里,注意我们用 uuid()
替换了 normal id()
;并使其成为主键。
让我们把它封装成 Trait
接下来,我们可以实现 Laravel
生命周期挂钩,以确保在创建此模型的新实例时分配了 UUID
。我们可以直接在模型中编写代码,但是如果你要在多个模型中使用 UUID
,我建议用 Trait
(我在这篇开发文章中学到了这一点,非常感谢 Dev)。trait
基本上允许你创建功能,并通过 use 关键字调用它在多个模型中使用。
要创建新的 Trait
,请创建一个 \App\Http\Traits
文件夹(这仅仅是我的爱好,你也可以将其放到其他位置),并为 Trait
创建一个新文件。我们将调用文件 UsesUuid.php。
这是 trait 的具体代码:
<?php
namespace App\Http\Traits;
use Illuminate\Support\Str;
trait UsesUuid
{
protected static function bootUsesUuid() {
static::creating(function ($model) {
if (! $model->getKey()) {
$model->{$model->getKeyName()} = (string) Str::uuid();
}
});
}
public function getIncrementing()
{
return false;
}
public function getKeyType()
{
return 'string';
}
}
使用 \Illuminate\Support\Str
轻松生成 UUID.。getIncrementing()
方法告诉 Laravel 该模型的主键不会自增 (因为我们设置的是 false), 而 getKeyType() 方法告诉 Laravel 该模型的主键是字符串类型。bootUsesUuid() 方法允许我们使用 Laravel 强大的生命周期钩子。你可以 在这来了解更多详细信息。基本上我们的代码已经可以告诉 Laravel,当创建该模型的新实例时,为其设置 UUID 主键!
现在,我们可以使用use关键字在模型上轻松实现此特征。
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
...
class Employee extends Model
{
...
use \App\Http\Traits\UsesUuid;
...
}
将UUID引用为外键
要将表上的UUID引用为外键,只需更改表上外键字段的类型。如下…
Schema::create('another_table', function(Blueprint $table) {
$table->id();
$table->unsignedBigInteger('employee_id');
$table->string('some_field');
$table->foreign('employee_id')
->references('id')
->on('shifts')
->onDelete('cascade');
});
… 我们在引用employee_id外键时创建了一个无符号大整型的数据类型,对此进行如下修改:
Schema::create('another_table', function(Blueprint $table) {
$table->id();
$table->uuid('employee_id');
$table->string('some_field');
$table->foreign('employee_id')
->references('id')
->on('shifts')
->onDelete('cascade');
});
那样简单!还有一件事…
UUID和多态关系
您可能会发现自己通过自己的操作或要引入的包以多态关系引用了该模型。在迁移中,该表可能看起来像这样:
public function up()
{
Schema::create('some_package_table', function (Blueprint $table)
{
$table->bigIncrements('id');
$table->morphs('model');
...
}
}
在这里,morphs()方法将在数据库中创建两个字段,即无符号大整型类型的model_id和字符串类型的model_type。问题在于我们的模型现在使用的是UUID而不是递增的整数ID,因此这会给您带来错误,并显示类似以下内容::
Data truncated for column 'model_id' at row 1
我们现在需要model_id字段来支持我们的新UUID,它的类型是CHAR(36)。别担心!Laravel让这件事变得超级简单,你不需要手动做这件事。只需将迁移更改为:
public function up()
{
Schema::create('some_package_table', function (Blueprint $table)
{
$table->bigIncrements('id');
$table->uuidMorphs('model');
...
}
}
爱Laravel的另一个原因!编码愉快!
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
good
very good
下一个项目用用看!
改动太大 可以Aes加密解密来处理
命名空间可以用这个
namespace App\Http\Model\Traits;
,看到就知道模型用的,日后 trait 多了呢?还有就是 DB::table(‘user’) 可以用 uuid 吗?create 可以吗?
这个时候需要手动指定 uuid 了吧?
个人意见,欢迎交流
个人建议使用雪花id,第一还是bigint,数据库效率高,第二个并发可以用redis来解决,第三,相对系统改动不大,在model的creating里面加一个id生成的方法就行了。
哈希数据 ID 这个更加方便
个人建议 多设置一个uuid 访问的时候 访问 uuid 关联的时候 走自增id
我是继续用自增id 在出口进行自动加密id,核心不动,入口路由中间件自动解密