【问题标题】:Generating my own Eloquent model insert IDs - How to avoid PK Collisions?生成我自己的 Eloquent 模型插入 ID - 如何避免 PK 冲突?
【发布时间】:2015-06-28 01:04:14
【问题描述】:

也许这是一个愚蠢的问题,因为我应该将 PK 增量推迟到 MySql 本身,但我的情况很奇怪。

基本上为了在我的系统中处理版本控制和批准,我有revision_batch 表,它是用户希望插入或更新到数据库的提交中的东西的集合。它具有batch_id、提交者的user_idapproved 值等列。

它也是revisions 表中项目集合的父级。修订表包含 table_namekeyold_valuenew_value 之类的内容。我使用它来存储某人希望进行的可能不会自动批准的更改。

当某人无权访问“任务”表时,他们更改了任务的名称,将创建一个新的revision_batch,并使用@ 创建一个新的revision 987654332@="tasks", key=[无论任务 ID 是什么], old_value="我的旧任务名称", new_value="我的新任务名称"。

当批准者批准此批次时,我的代码将快速浏览批次中的修订并执行更新或插入数据库。

我的问题是在同一批次中执行父子关系时。如果我正在创建一个新的task 并想在同一批次中为其分配一个task_item,那么我需要知道task 得到了什么PK,以便我可以给task_item 一个“ task_id"。

如果我要为task 创建一个新的revision,我可能会做类似的事情

select max(id)+1 as newId from tasks

作为新的 id 注入。但由于我可能已经有一个具有该 ID 或更高 ID 的待处理任务插入修订,因此我还要检查

select max(key) + 1 as newId 
from revisions 
inner join revision_batches on revisions.batch_id = revision_batches.id
where table_name='revisions' and approved = 'P'

用于分配更高的 id。这样,我在 tasks 表中有 id 1-9,在 revisions 表中有 10-12 待处理,使用 Laravel 的 Eloquent 模型类的任何新直接插入都将被覆盖以检查任务和修订,并将插入 id 13 . 这避免了实际粘合行和可能的修订行之间的冲突。它还允许我在单个批次中创建父级和多个子级,因为我会在执行过程中确定他们的 ID。

这一切都很好。

我的问题是,如果我有两个 revisions 同时发生(例如,在一毫秒内),它们将异步获取相同的下一个 ID 以使用,两者都创建 key = 相同的修订编号,然后只有一个会通过,另一个会在PK冲突时失败。

我的问题是:有没有办法强制它是线程安全的或同步完成,以避免同一控制器方法的两个实例同时执行并且都获取相同的 ID 来使用?我可以一次将一个方法锁定到一个实例吗?如果没有,有没有更好的方法可以处理 PK 生成?我这样做的唯一原因是事先知道要插入的密钥。但是由于框架中的自定义代码是处理 PK 生成而不是数据库,这给我带来了这个主要问题。偶尔会发生,但只有当我强制同一方法同时执行 4 次时才会发生。

我知道我可以避免同时插入许多东西的大多数情况,但这并不意味着将来随机两个用户不会同时按 enter 并且重新创建此问题。

有什么想法吗?

谢谢!

【问题讨论】:

    标签: php mysql laravel laravel-4 eloquent


    【解决方案1】:

    对于此类问题,我使用 UUID 4 (Universally unique identifier),我的情况有点不同,因为我在 74 个不同位置有一个系统,但需要提取所有交易记录并集成到一个合并系统中,所以我的 PK 需要在所有服务器上都是唯一的以避免冲突。

    在 laravel 中我使用 this excelent package 来生成 UUID

    我希望这对你有用。

    【讨论】:

    • 我不敢相信我从来没有想过这样的事情!我今晚会试试这个。我以前从未将 UUID 用作 PK,所以这会很有趣。这也掩盖了一些我喜欢的作为路由 URL 的一部分可见的 ID。看到 ..../task/1/.... 总是让我畏缩。谢谢!
    • 我继续并追溯获得了在每次插入操作时为我的自定义 Eloquent 模型类的继承者自动生成的唯一 ID。这现在完美无缺。谢谢你的想法。
    【解决方案2】:

    使用队列来保存您的修订。

    队列是同步的,因此不会发生密钥冲突。

    来源:http://laravel.com/docs/4.2/queues

    【讨论】:

    • 谢谢,我会调查的。我以前从未听说过在 Laravel 中排队!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-16
    • 1970-01-01
    • 1970-01-01
    • 2021-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多