Hibernate 获取带有字符串前缀的下一个 ID

Posted

技术标签:

【中文标题】Hibernate 获取带有字符串前缀的下一个 ID【英文标题】:Hibernate get next ID with string prefix 【发布时间】:2018-01-18 08:15:58 【问题描述】:

我有一个关于 Hibernate 中的主键生成的问题。我正在维护现有的注册表系统。当前设计使用字符串作为主键。规则类似于"EXE" + max()。下面是表格的样子。

+----------+---------------------------+----------------+
| ID       |   Email                   |   Name         |
+----------+---------------------------+----------------+
|EXE1      | email1@gmail.com          | Name 1         |
+----------+---------------------------+----------------+
|EXE5      | email5@gmail.com          | Name 5         |
+----------+---------------------------+----------------+
|EXE14     | email14@gmail.com         | Name 14        |
+----------+---------------------------+----------------+
|EXE15     | email15@gmail.com         | Name 15        |
+----------+---------------------------+----------------+

目前我使用下面的代码来生成 ID。

Long rowCount = (Long) getSession().createCriteria(Exemption168DB.class).setProjection(Projections.rowCount()).uniqueResult();
if(rowCount == null)
    rowCount = 0L;
return String.format("%s%d", CommonConstant.EXEMPTION_KEY_PREFIX, rowCount + 1);

但问题是;它使用行数来获取下一个序列数字。所以在上述情况下,该方法将返回EXE5(此ID已存在于表中,因此抛出异常)因为表中的行数为4,然后递增1。我需要的是EXE16

非常感谢任何帮助。额外信息,我们使用 Informix 作为数据库引擎。

【问题讨论】:

为什么不查询最后插入的id呢?类似的东西(需要适应informix)。 ***.com/questions/21829023/… 检查***.com/questions/31158509/…是否能解决您的问题 按降序排列并限制(1)。 您使用的是 Hibernate 还是 JPA? 如果你使用hibernate,你可以实现你自己的ID生成器,见here。 【参考方案1】:

正如我在twocomments 中指出的,Informix 中可用的一种技术将使用触发器和SERIAL 列。另一种技术是使用 SEQUENCE 和存储过程。

下面是序列加存储过程的一些演示代码:

CREATE SEQUENCE registry_seq
    INCREMENT BY 3
    START WITH 37
    MINVALUE 21
    MAXVALUE 299
    CYCLE;

CREATE PROCEDURE get_next_registry_id() RETURNING VARCHAR(10) AS registry_id;

    DEFINE i INTEGER;
    DEFINE r VARCHAR(10);
    SELECT registry_seq.NEXTVAL INTO i FROM "informix".SysTables WHERE tabid = 1;

    LET r = "EXE" || i;

    RETURN r;

END PROCEDURE;

CREATE TEMP TABLE registry
(
    id              VARCHAR(10) NOT NULL UNIQUE,
    email           VARCHAR(64) NOT NULL UNIQUE,
    name            VARCHAR(64) NOT NULL UNIQUE
);

INSERT INTO registry VALUES('EXE1', 'email1@gmail.com', 'Name 1');
INSERT INTO registry VALUES('EXE5', 'email5@gmail.com', 'Name 5');
INSERT INTO registry VALUES('EXE14', 'email14@gmail.com', 'Name 14');
INSERT INTO registry VALUES('EXE15', 'email15@gmail.com', 'Name 15');

INSERT INTO registry VALUES(get_next_registry_id(), 'email' || registry_seq.currval || '@example.com', 'User ID ' || registry_seq.currval);
INSERT INTO registry VALUES(get_next_registry_id(), 'email' || registry_seq.currval || '@example.com', 'User ID ' || registry_seq.currval);
INSERT INTO registry VALUES(get_next_registry_id(), 'email' || registry_seq.currval || '@example.com', 'User ID ' || registry_seq.currval);

SELECT * FROM registry ORDER BY id;

显然,您应该为CREATE SEQUENCE 语句选择不同的控制值。对于我的测试(开始在不同的桌子上工作),这些工作对我来说是半方便的。

FROM "informix".systables WHERE tabid = 1 是用于选择单行数据的标准 Informix 惯用语。系统目录有1tabid记录的systables表。在现代版本的 Informix 上(意味着您应该运行的任何东西;不过可能有些人仍在运行旧版本),您可以从 sysmaster:sysdual(或者,如果您真的很安全,sysmaster:"informix".sysdual)中进行选择,即单行表,单列。

最终输出为:

EXE1    email1@gmail.com        Name 1
EXE14   email14@gmail.com       Name 14
EXE15   email15@gmail.com       Name 15
EXE37   email37@example.com     User ID 37
EXE40   email40@example.com     User ID 40
EXE43   email43@example.com     User ID 43
EXE5    email5@gmail.com        Name 5

请注意,字母数字 ID 的缺点之一是排序顺序不是数字而是字典顺序。

【讨论】:

【参考方案2】:

创建一个自定义 ID 生成器类,用于查询最后插入的 id 并提取数字部分。选择字符串长度等于 ID 的最大字符串长度的所有 id,按降序排列并将结果集限制为 1。然后像您在问题中所做的那样递增数字。

【讨论】:

按id列降序排列,例如表中有2条记录EXE9和EXE10。返回值为 EXE9,因为该列是 varchar。 添加 where 子句,指定 id 的字符串长度必须等于所有 id 的最大字符串长度 感谢您的建议。是的,我一开始也是这么想的。要先按字符串长度对 id 进行排序,然后得到最长的,然后仅根据结果进行排序。但是仅仅生成 id 有点复杂。 对不起,我对informix一无所知(你现在可能已经猜到了:))。最后一个建议,如果可能的话,创建一个跟踪 ids 数字的第二个表。在您的自定义 id 生成器类中更新它。祝你好运。 没问题。我想我会坚持首先根据字符串长度进行排序的逻辑。创建新表来存储当前最高数字是最好的解决方案。不幸的是,我们没有权限这样做,只是要求他们添加新表,必须经历很多过程。叹。再次感谢?

以上是关于Hibernate 获取带有字符串前缀的下一个 ID的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces 1334C - Circle of Monsters(差值取前缀和 / 贪心)

需要在SoapUI中的下一个请求中使用的修剪响应值

在 python BeautifulSoup 上获取带有特定前缀的超链接

从Hibernate查询中获取SQL String

为啥 Hibernate 不使用序列表中的下一个序列值?

从带有前缀的 Azure Key Vault 获取所有机密