【问题标题】:Hibernate and padding on CHAR primary key column in OracleOracle中CHAR主键列的休眠和填充
【发布时间】:2010-12-26 22:32:51
【问题描述】:

我在 Oracle 中使用带有 char(6) 列的 Hibernate 时遇到了一点问题。这是表的结构:

CREATE TABLE ACCEPTANCE
(
   USER_ID char(6) PRIMARY KEY NOT NULL,
   ACCEPT_DATE date
);

对于用户 ID 少于 6 个字符的记录,我可以在使用 SQuirreL 运行查询时选择它们而无需填充用户 ID。 IE。如果存在用户 id 为“abc”的记录,则以下返回记录。

select * from acceptance where user_id = "abc"

不幸的是,当通过 Hibernate (JPA) 进行选择时,以下返回 null:

em.find(Acceptance.class, "abc");

如果我填充值,它会返回正确的记录:

em.find(Acceptance.class, "abc   ");

我正在处理的模块从系统的其他部分获取用户 ID。有没有更好的方法让 Hibernate 工作,而不是在将用户 ID 提供给 Hibernate 之前将其调整为特定长度? (如果长度发生变化,可能会出现维护问题)

【问题讨论】:

  • “如果长度发生变化”。如果发生这种情况,您的主键会发生变化,您需要担心更多问题。

标签: java oracle hibernate jpa


【解决方案1】:

这是上帝告诉你永远不要使用 CHAR() 作为主键的方式:-)

但是,说真的,因为您的 user_id 在您的实体 Hibernate 的 Oracle 方言中被映射为字符串,因此会将其转换为 varchar。由于 Hibernate 对其所有查询都使用准备好的语句,因此语义会延续(与 SQuirreL 不同,其中值被指定为文字,因此转换方式不同)。

基于 Oracle 的type conversion rules 列值然后提升为varchar2 并进行比较;因此你没有得到任何记录。

如果你不能改变底层的列类型,你最好的选择可能是使用Oracle方言支持的HQL查询和rtrim()函数。

【讨论】:

  • 我想过做类似 em.createQuery("from Acceptance where trim(userId) = :userId");但这会破坏主键上的索引吗?
  • 您只需要rtrim(),而不是完整的trim() - 仍然应该使用非空白字符的索引。
  • 你确定吗?我在 Google 上发现一些论坛帖子说 rtrim 确实会导致表扫描。
  • 如果没有获取常规索引,您始终可以专门为rtrim() 创建基于函数的索引。
  • 我最终努力将列更改为 varchar2。我接受了这个答案,因为我认为它提供了最丰富的信息。
【解决方案2】:

您的模块如何从系统的其他部分获得未填充的值?

根据我的理解,如果系统的其他部分不改变 PK,他们应该从数据库中读取 6 个字符并一路传递 6 个字符——这样就可以了。唯一的例外是生成 PK 时,在这种情况下可能需要对其进行填充。

您可以规避该问题(通过每次必要时修剪或填充该值),但它不会预先解决您的 PK 处理不一致的问题。要提前解决问题,您必须要么

  • 总是从模块的其他部分接收 6 个字符
  • 使用varchar2 正确处理动态大小

如果你不能提前解决问题,那么你确实需要要么

  • 必要时在整个位置添加修剪/填充
  • 在 DAO 中添加修剪/填充(如果有)
  • 如果可行,请在用户类型中添加修剪/填充(来自 N. Hughes 的建议)

【讨论】:

  • 我什至会说如果数据库类型是 CHAR(6),那么它在语义上期望该数据库的客户使用 6 个字符,句号。所以要么必须更改数据库定义,要么客户需要遵守:)
猜你喜欢
  • 2012-09-04
  • 2011-04-09
  • 1970-01-01
  • 2017-08-04
  • 2011-12-12
  • 1970-01-01
  • 2012-03-21
  • 2012-03-15
  • 2012-01-25
相关资源
最近更新 更多