php使用redis生成自增序列号码,Laravel 中使用 Redis 生成自增主键

Laravel 中使用 Redis 生成自增主键

终于,开始使用 Laravel 开发正式项目,虽然看过很多文章,做过一些练习,但是真搞起来,仍然是个丈二。

考虑到国情,项目一开始就考虑分库分表的事情,数据库管控的自增主键值,不利于将来搞大事,但是又不想使用 uuid,所以要对所有表主键值进行统一管理,于是应用 Redis 生成.

主键值的填充可以在 Model 事件 creating 的时候进行,这里有两种方式,详情请见下文。

1. 创建主键值生成器

独立出来,在某些情况可以单独调用。

namespace App\Support\Database;

use Illuminate\Support\Facades\Redis;

use Illuminate\Database\Eloquent\Model;

class PrimaryKeyValueGenerator

{

/**

* 自增值

*

* @param string $key

* @return integer

* @author Chuoke

*/

public function incrementId($key = 'model-primary-key')

{

return Redis::incr($this->formatKey($key));

}

/**

* 给模型实例生成主键值

*

* @param Model $model

* @return void

* @author Chuoke

*/

public function incrementIdOfModel(Model $model)

{

$key = $this->buildKeyOfModel($model);

return self::incrementId($key);

}

/**

* 给 model 实例生成一个主键 key

*

* @param Model $model

* @return string

* @author Chuoke

*/

public function buildKeyOfModel(Model $model)

{

return implode('_', ['table', $model->getTable(), 'id']);

}

/**

* 格式化 key

*

* @param string $key

* @return string

* @author Chuoke

*/

public function formatKey($key)

{

return strtoupper($key);

}

}

2. 主键填充

方便起见,把填充方法封成 trait.

namespace App\Models\Traits;

use App\Support\Facades\PrimaryKeyValueGenerator;

trait MustFillPrimaryKey

{

/**

* 启动填充主键值事件

*

* @return void

* @author Chuoke

*/

public static function bootMustFillPrimaryKeyEvent()

{

static::creating(function ($model) {

$model->fillPrimaryKey();

});

}

/**

* 填充主键值

*

* @param \App\Modells\Model $model

* @return void

* @author Chuoke

*/

public function fillPrimaryKey()

{

if ($this->needFillPrimaryKey()) {

$id = PrimaryKeyValueGenerator::incrementIdOfModel($this);

$this->setAttribute($this->getKeyName(), $id);

}

}

/**

* 判断是否需要填充主键值

*

* @return boolean

* @author Chuoke

*/

public function needFillPrimaryKey()

{

return empty($this->getKey())

// && $this->getIncrementing()

&& $this->getKeyName() !== false;

}

}

设置 incrementing = false `` 避免执行 insertAndSetId() 导致插入后主键值为 0 `

3. 事件监听

Model 中的 trait 可以做一个和 trait 名称一样的 boot 方法,如:bootbootMustFillPrimaryKey, 这样在启动的时候会自动启动,所以上面有一个这个类似的方法,只是个备份,如果是个别的需要这样的操作,使用这种方式很方便。

创建一个事件处理

namespace App\Events;

use Illuminate\Queue\SerializesModels;

use Illuminate\Database\Eloquent\Model;

use Illuminate\Foundation\Events\Dispatchable;

use Illuminate\Broadcasting\InteractsWithSockets;

class FillModelPrimaryKey

{

use Dispatchable, InteractsWithSockets, SerializesModels;

public $model;

public function handle($e, $payload)

{

if (is_array($payload)) {

foreach ($payload as $model) {

$this->handle($e, $model);

}

} else if ($payload instanceof Model && \method_exists($payload, 'fillPrimaryKey')) {

$payload->fillPrimaryKey();

}

}

}

然后在 App\Providers\EventServiceProvider 中注册监听所有的模型创建事件.

/**

* The event listener mappings for the application.

*

* @var array

*/

protected $listen = [

'eloquent.creating: *' => [

FillModelPrimaryKey::class,

],

];

这里有个小坑,调了半天,回眸了若干次源码才发现,那个 * 前面居然有个空格 ?

4. 无侵入式方案

下面这种方式是全局性的,更灵活,不需要引入 trait,合理的利用了框架提供的能力,第三方扩展也会使用该方式生成主键,如果某些表有特殊的自定义情况,可以使用上面那种方式,当然也可以结合使用。

namespace App\Events;

use Illuminate\Queue\SerializesModels;

use Illuminate\Database\Eloquent\Model;

use App\Support\Facades\PrimaryKeyValueGenerator;

use Illuminate\Foundation\Events\Dispatchable;

use Illuminate\Broadcasting\InteractsWithSockets;

class FillModelPrimaryKey

{

use Dispatchable, InteractsWithSockets, SerializesModels;

/**

* Create a new event instance.

*

* @return void

*/

public function __construct()

{

//

}

public function handle($e, $payload)

{

if (is_array($payload)) {

foreach ($payload as $model) {

$this->handle($e, $model);

}

} else if ($payload instanceof Model) {

if ($payload->getIncrementing() && empty($payload->getKey())) {

// 关闭主键自增,以避免内部获取自增主键值逻辑(insertAndSetId())导致主键被置空

$payload->setIncrementing(false);

$payload->setAttribute($payload->getKeyName(), $this->generatePk($payload));

}

}

}

/**

* 生成主键值

*

* @return integer

* @author Chuoke

*/

protected function generatePk($model)

{

return PrimaryKeyValueGenerator::getIdOfModel($model);

}

}

总结

无论是自增主键还是普通主键,只要有主键就行。统一生成有利于分库分表,还可以方便做其他特殊化的事情,这只是一个思路,虽然能够运用 Laravel 进行开发,但是还不够了解,有很多需要优化的地方,自定义框架的功能可以对框架进行深入的了解,慢慢进步吧。

初出茅庐,一知半解,望有识之士多多指教 ?

本作品采用《CC 协议》,转载必须注明作者和本文链接

初出茅庐,一知半解,望有识之士多多赐教。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值