【问题标题】:Configure Hibernate to use Oracle's SYS_GUID() for Primary Key配置 Hibernate 以使用 Oracle 的 SYS_GUID() 作为主键
【发布时间】:2010-10-25 05:03:36
【问题描述】:

我正在寻找一种在插入新行时让休眠以使用 oracle 的SYS_GUID() 函数的方法。目前我的数据库表默认使用SYS_GUID(),所以如果hibernate只是生成省略了该值的SQL,它应该可以工作。

我一切正常,但它目前正在使用 system-uuid 生成器在代码中生成 UUID/GUID:

@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
@Column(name = "PRODUCT_ID", unique = true, nullable = false)
public String getId() {
    return this.productId;
}

这很好,但我更希望 guid 由数据库生成,这样它们将是连续的并且可能具有更好的性能。另外,我只想知道如何配置它。

我使用注解进行配置,但 xml 配置示例也很棒。

这是一个示例表定义(以防万一):

CREATE TABLE SCHEMA_NAME.PRODUCT
(
    PRODUCT_ID RAW(16) DEFAULT SYS_GUID() NOT NULL,
    PRODUCT_CODE VARCHAR2(10 CHAR) NOT NULL,
    PRODUCT_NAME VARCHAR2(30 CHAR) NOT NULL,
    PRODUCT_DESC VARCHAR2(512 CHAR)
)

更新:

Mat 使用“guid”的解决方案有效,这是生成的 sql:

Hibernate: 
    select rawtohex(sys_guid()) 
    from dual
Hibernate: 
    insert into PRODUCT
    (PRODUCT_CODE, PRODUCT_DESC, LOB_ID, PRODUCT_NAME, PROVIDER_ID, PRODUCT_ID) 
    values (?, ?, ?, ?, ?, ?)

似乎无法在插入中使用列默认值,因此需要在应用程序生成的 guid 和数据库往返之间进行选择。

【问题讨论】:

    标签: java oracle hibernate guid uuid


    【解决方案1】:

    您也许可以使用“guid”生成器。请参阅 Hibernate 论坛中的 this post。看起来他们不久前使用 SYS_GUID() 添加了对 Oracle 的支持,但 documentation 仍然表示他们只支持 SQL Server 和 MySQL。

    我还没有使用过 JPA 注释,但这里有一个使用 XML 配置的示例:

    <id name="PRODUCT_ID">
      <generator class="guid" />
    </id>
    

    编辑:关于你的第二个问题,我想你是在问为什么 Hibernate 不能做这样的事情:

    INSERT INTO PRODUCT (PRODUCT_ID, /* etc */)
    SELECT SYSGUID(), /* etc */
    

    原因是 Hibernate 必须知道对象的 ID 是什么。例如,考虑以下场景:

    1. 您创建一个新的 Product 对象并保存它。 Oracle 分配 ID。
    2. 您将产品从 Hibernate 会话中分离出来。
    3. 您稍后重新附加它并进行一些更改。
    4. 您现在想要保留这些更改。

    在不知道 ID 的情况下,Hibernate 无法执行此操作。它需要 ID 才能发出 UPDATE 语句。所以org.hibernate.id.GUIDGenerator的实现必须事先生成ID,然后在INSERT语句中重复使用。

    如果您使用数据库生成的 ID(包括支持它的数据库上的自动增量),这与 Hibernate 无法进行任何批处理的原因相同。在一次插入大量对象时,使用其中一个 hilo 生成器或其他一些 Hibernate 生成的 ID 机制是获得良好性能的唯一方法。

    【讨论】:

    • 这可行,但产生了一些额外的 sql,请参阅我的更新。感谢您的宝贵时间。
    • 嗨瑞恩。我编辑了答案以尝试回答您的后续问题。
    • 仅供参考:通过注释执行此操作很简单:@GenericGenerator(name = "guid", strategy = "guid")
    • 对我来说,我必须给出两个注释 @GeneratedValue(generator=”db-guid”) @GenericGenerator(name=”db-guid”, strategy = “guid”)
    【解决方案2】:

    我有与主题启动器相同的任务。感谢 @Matt Solnit 的建议,我使用了这样的注释:

    @Id
    @NotNull
    @Column(name = "UUID")
    @GenericGenerator(name = "db-uuid", strategy = "guid")
    @GeneratedValue(generator = "db-uuid")
    private String uuid;
    public String getUuid() { return uuid; }
    public void setUuid(String uuid) { this.uuid = uuid; }
    

    strategy = "guid"String 类型是解决方案的重要组成部分。

    在持久化新实体之前 Hibernate 发出 SQL 查询:

    select rawtohex(sys_guid()) from dual
    

    我的设置:Oracle 11、Hibernate 4.3.4.Final、Spring 3.2.x。如果使用char(32),则表中的字段为raw(16),以实现高效存储和更小的索引大小。

    当我尝试使用 java.util.UUID 作为 ID 字段类型时,我从 Hibernate 收到关于持久化新实体的错误(它尝试将 String 类型设置为 java.util.UUID 字段)。

    我还将javax.xml.bind.DatatypeConverter 用于非Hibernate 查询(Spring JDBC 帮助程序),用于将转换传递给byte[]

    String query = "insert into TBL (UUID, COMPANY) values (:UUID, :COMPANY)";
    MapSqlParameterSource parameters = new MapSqlParameterSource()
        .addValue("COMPANY", repo.getCompany())
        .addValue("UUID", DatatypeConverter.parseHexBinary(signal.getUuid()));
    namedJdbcTemplate.update(query, parameters);
    

    用于提取:

    ResultSet rs;
    sig.id = DatatypeConverter.printHexBinary(rs.getBytes("UUID"));
    

    所有 web 控制器都得到如下代码:

    025131763FB19522E050010A106D11E9
    

    没有{-} 字符(如果你记得的话,UUID 的通常表示是{a-b-c-d-x-y})。这种表示已经 URL 编码干净和安全。对于String 类型,您不需要实现PropertyEditorConvertor

    @RequestMapping(value = {"/signal/edit/{id}.htm"}, method = RequestMethod.POST)
    public String handleEditRequest(
            @PathVariable("id") String id,
    

    与尝试使用 jaa.util.UUID 的失败进行比较,我需要在其中编写:

    @Component
    public static class UUIDPropertyEditor extends PropertyEditorSupport {
        @Override
        public void setAsText(final String str) {
            if (str == null || str.isEmpty()) {
                setValue(null);
                return;
            }
            setValue(UUID.fromString(str));
        }
    }
    private @Autowired UUIDPropertyEditor juuidPE;
    
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(UUIDPropertyEditor.class, juuidPE);
    }
    

    为了使用:

    @PathVariable("id") UUID id,
    

    【讨论】:

      【解决方案3】:

      我认为您可以通过将生成器设置为原生来做到这一点。我不太确定如何在 Hibernate 中执行此操作,但在 NHibernate 中,您会在 XML 中执行类似的操作:

      <id column="PRODUCT_ID">
        <generator class="native"/>
      </id>
      

      【讨论】:

      • "native" 是 Oracle 中的序列。因此,我对此表示怀疑。但尝试一下也不错。
      • 顺便说一句,您指定在 NHibernate 中执行此操作,但没有指定数据库,这就是这里最关心的问题。
      • 很有可能我错了,我刚刚开始使用 NHibernate。
      猜你喜欢
      • 2015-09-10
      • 2014-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-16
      • 1970-01-01
      相关资源
      最近更新 更多