Grails 2 Gorm Hibernate 4:2 个循环服务器导致 jdbc4.MySQLIntegrityConstraintViolationException:键“PRIMARY”的重复条目“493”

问题描述 投票:0回答:1

我正在开发一个 Grails 2.5 版项目。我面临 Gorm / Hibernate 的问题。该项目部署在两台服务器上,每台服务器都会以循环方式收到调用。当我们使用其中一个 API 时,它会尝试创建一个新实体并将其保留在数据库中。

问题是,当我们调用这个 API 时,几乎所有其他请求都会失败,并显示如下错误消息:

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '493' for key 'PRIMARY'

我尝试设置 id 值,但它没有采用该值,而是尝试它自己的值。我还尝试在子类中映射

id generator 'assigned'
(无法触摸将生成器设置为标识的基类,因为还有其他子类)

我的问题是,我们如何清除hibernate认为的主键的下一个值?我尝试禁用二级缓存和查询缓存,但这不起作用。我们是否有办法以编程方式清除 Hibernate 缓存,以便它转到数据库以查看最大 id 值是多少?不仅如此,如果您知道任何其他解决方法,也请发布。

编辑

以下是基类和子类的映射:

基类

abstract class BaseEntity implements Serializable {
    static mapping = {
        tablePerHierarchy false  // avoid creating the base_domain table
        tablePerConcreteClass true
        id generator: 'identity'
        createdDate index: true  // index this column in each subclass table
        inUse index: true  // index this column in each subclass table
    }
}

少儿班:

class ActualEntity1 extends BaseEntity {

    static mapping = {
        id generator: 'assigned'
    }
}

这些是 Gorm 域类。我故意删除了类的其他字段。

hibernate grails grails-orm
1个回答
0
投票

如果调用相同的 API,可能会出现竞争条件。所以,目前,我想要的第一件事就是不要像现在这样频繁地出现这个问题。
后来,如果真的发生了,我们可以考虑在 Redis 中使用一个可以继续递增的公共密钥。

我正在尝试所有不涉及更改数据库架构的解决方案

确实,以循环方式使用多个服务器可能会导致主键下一个值的竞争条件。当您使用

identity
生成器时,Hibernate 依赖底层数据库来生成 ID,通常是通过自动增量列。

在多服务器环境中处理这种情况的最直接方法是使用序列生成器,数据库将始终生成唯一标识符,确保没有重复的键。
然而,这涉及修改数据库架构。

您可以开始并尝试使用 UUID(通用唯一标识符)作为主键。 UUID 的生成方式几乎可以保证它们是唯一的。
这不需要更改您的数据库架构,但您需要修改域对象以支持 UUID 作为主键。

class ActualEntity1 extends BaseEntity {
    UUID id

    static mapping = {
        id generator: 'uuid'
    }
}

它确实具有几乎消除碰撞可能性的优点。
但是:UUID 比常规整数 ID 更大,并且在某些情况下可能更难管理。


由于您已尝试在

assigned
中使用
ActualEntity1
生成器,因此您可以通过在数据库中查询最大当前 ID,然后向其添加 1,以编程方式确定下一个 ID。
然而,这存在潜在的竞争条件风险。您必须实施一些锁定机制来确保 ID 不重复。


您还可以依赖外部服务:

  • 构建一个单独的微服务,仅负责生成唯一 ID。每次需要持久保存新实体时,都会首先调用此服务来检索新 ID。这种方法的主要优点是 ID 生成逻辑被抽象化和集中化。但这会引入另一个故障点和额外的延迟。

  • 使用ZooKeeperetcd等分布式系统工具来维护全局唯一ID生成器。这些系统可以维护分布式锁,确保您始终获得唯一的 ID,即使跨多个服务器也是如此。然而,引入这样的新系统组件可能很复杂。
    请参阅插图“使用 Zookeeper 生成分布式 UUID”,来自 Phani Kumar Yadavilli,2019 年 5 月。

© www.soinside.com 2019 - 2024. All rights reserved.