3

我有一个关于 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 作为数据库引擎。

4

2 回答 2

1

正如我在两条 评论中所指出的,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 习惯用法。系统目录有记录的systables表。在 Informix 的现代版本(意味着您应该运行的任何东西;尽管可能有些人仍在运行旧版本)上,您可以选择(或者,如果您真的很安全,)这是一个带有单列。tabid1sysmaster:sysdualsysmaster:"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 的缺点之一是排序顺序不是数字而是字典顺序。

于 2018-01-19T08:20:33.333 回答
1

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

于 2018-01-18T09:28:35.833 回答