Php 使用UUID作为Laravel 5的主键
我正在尝试创建具有主键的表,主键是定义为Php 使用UUID作为Laravel 5的主键,php,mysql,laravel,laravel-5,eloquent,Php,Mysql,Laravel,Laravel 5,Eloquent,我正在尝试创建具有主键的表,主键是定义为binary(16)的UUID,而不是默认的自动递增id字段 我已经成功地使用原始SQL语句创建了迁移,尽管DB::statement类似这样: DB::statement("CREATE TABLE `binary_primary_keys` ( `uuid` binary(16) NOT NULL DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0',
binary(16)
的UUID,而不是默认的自动递增id
字段
我已经成功地使用原始SQL语句创建了迁移,尽管DB::statement
类似这样:
DB::statement("CREATE TABLE `binary_primary_keys` (
`uuid` binary(16) NOT NULL DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0',
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;");
但是,我很难让模型正常工作。我遵循了可用的教程。我这样定义了我的模型:
class UuidModel extends Model
{
public $incrementing = false;
public $primaryKey = 'uuid';
/**
* The "booting" method of the model.
*
* @return void
*/
protected static function boot()
{
parent::boot();
/**
* Attach to the 'creating' Model Event to provide a UUID
* for the `id` field (provided by $model->getKeyName())
*/
static::creating(function ($model) {
$model->{$model->getKeyName()} = (string)$model->generateNewId();
echo($model->{$model->getKeyName()});
});
}
/**
* Get a new version 4 (random) UUID.
*/
public function generateNewId()
{
return Uuid::generate();
}
}
其中Uuid
是webpacser\Uuid
的别名
我遇到的一个问题是,我无法从雄辩的中导出UuidModel
,如教程中所述。事实上,我没有看到一个有口才的班。我是从模型
衍生出来的。我猜教程是用拉维4写的
如果能在Laravel5中帮助实现UUID作为主键的表,我将不胜感激
编辑1:
因此,如果我这样定义我的类:
use Illuminate\Database\Eloquent
class UuidModel extends Eloquent { ... }
我得到以下错误:
PHP Fatal error: Class 'Illuminate\Database\Eloquent' not found in /home/vagrant/transactly/app/UuidModel.php on line 8
PHP Fatal error: Class 'App\Eloquent' not found in /home/vagrant/transactly/app/UuidModel.php on line 8
如果删除use illumb\Database\elount
行,则会出现以下错误:
PHP Fatal error: Class 'Illuminate\Database\Eloquent' not found in /home/vagrant/transactly/app/UuidModel.php on line 8
PHP Fatal error: Class 'App\Eloquent' not found in /home/vagrant/transactly/app/UuidModel.php on line 8
编辑2:
我发现在创建UuidModel
的实例时,从未调用static::creating
事件
我尝试在AppServiceProvider
中设置创建
事件侦听器,但也没有调用它。有趣的是,creating
事件也不是为常规的Laravel生成的模型User
调用的
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
/**
* Attach to the 'creating' Model Event to provide a UUID
* for the `id` field (provided by $model->getKeyName())
*/
echo "Booting...\n";
UuidModel::creating(function ($model) {
echo "Creating Uuid Model...\n";
$model->{$model->getKeyName()} = (string)$model->generateNewId();
});
User::creating(function($user){
echo "Creating User Model...";
$user->name = 'Forced Name in boot()';
});
}
public function register(){}
}
这是一个不使用事件的快速解决方案
UUidModel.php
<?php namespace App;
use \Illuminate\Database\Eloquent\Model;
use \Illuminate\Database\Eloquent\Builder;
class UuidModel extends Model
{
/**
* Insert the given attributes and set the ID on the model.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param array $attributes
* @return void
*/
protected function insertAndSetId(Builder $query, $attributes)
{
$keyName = $this->getKeyName();
$id = $attributes[$keyName] = $this->generateNewId();
$query->insert($attributes);
$this->setAttribute($keyName, $id);
}
/**
* Get a new version 4 (random) UUID.
*/
public function generateNewId()
{
return 'uuid!!' ;// just for test
}
}
?>
模型示例Car.php
<?php namespace App;
class Car extends UuidModel {
}
因此,我让它像一个魔咒一样工作(未经测试的单元测试):
类UuidModel扩展了雄辩的
是一个较老的(Laravel 4)构造。我们在Laravel 5中使用类UuidModel扩展模型
解决的办法是移动
UuidModel::creating(function ($model) {
echo "Creating Uuid Model...\n";
$model->{$model->getKeyName()} = (string)$model->generateNewId();
});
从AppServiceProvider::boot()
到EventServiceProvider::boot()
。无需进行其他更改。一切如期进行
我仍然不知道为什么(2)在EventServiceProvider
中起作用,而在AppServiceProvider
中不起作用,正如官方解释的那样。但从名字来看,这可能就是它的本意 将36chr UUID存储为二进制(16)的想法如何:
在IMO中,没有Laravel生成UUID有一个优势。也就是说,如果新记录(将来某一天)从应用程序外部插入到数据库中,UUID字段将正确填充
我的建议是:使用迁移创建UUID默认值触发器
(此触发器使数据库服务器在每次插入新客户时生成UUID)
无论如何,希望这对某人有所帮助:-)也尝试使用此软件包将自动生成和分配模型中的UUID字段,还可以通过UUID键显示和更新
您是否尝试使用字符(36)标识?不,我没有。我想char(36)的效率会低一些。我真的不知道,但我认为比较二进制文件在比较中没有相同的精度,如果你使用,你应该转换成二进制文件,对吗?我认为,在位级别上,二进制(16)只是一个数字,仅比常规int(4)大四倍,本文会有所帮助。整数比较总是比字符(36)比较快。你指给我看的那篇文章证明了比较是缓慢的。如果我冒昧猜测一下,我会说作者看到了减速,因为他使用了char(36)列作为pk而不是binary(16)。那么你是说你得到了一个错误,elount
类没有找到?如果是这样的话,请公布您得到的确切错误。我尝试了这种方法,但从未调用中的insertAndSetId
函数。实际上,我可以在基类的实现中看到,只有当$this->incrementing
为true
时,才会调用insertAndSetId
。在我的例子中,由于uuid
列不是递增的,所以我将$this->incrementing
设置为false
。使用这种方式,递增属性必须为true(默认值),只需查看汽车模型我将使用trait,而不是创建扩展基本模型的“uuid model”类。这样,您就可以添加和删除UUID功能,而无需更改它扩展的类。还有,我不知道你为什么在迁移中使用原始SQL?@MartinBean是的,现在我已经让它工作了,我将尝试traits。谢谢你的提示。我使用原始sql,因为AFAIK、SchemaBuilder不支持二进制列。我的UUID列是二进制的(16),以获得最大的效率。:在子标题“Available Column Types”下,您可以找到二进制的。@MartinBean我看到了,但这映射到了没有指定长度的BLOB类型。我不完全确定BLOB是否会像二进制(16)那样高效,二进制(16)基本上比INT大4倍。我相信MySQL不会在同一个表中存储BLOB值。为了使模型使用uuid而不是自动递增,我做了一个简单的特性。你可以在。它变得尽可能简单,因为测试很多选项会减慢已经很慢的进程:)。