配置Hibernate以将Oracle的SYS_GUID()用于主键

时间:2009-05-11 05:12:44

标签: java oracle hibernate guid uuid

我正在寻找一种让hibernate在插入新行时使用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)
)

UPDATE:

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和数据库往返之间。

3 个答案:

答案 0 :(得分:5)

您可以使用“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. 您现在想要坚持这些更改。
  5. 在不知道ID的情况下,Hibernate无法做到这一点。它需要ID才能发出UPDATE语句。因此org.hibernate.id.GUIDGenerator的实现必须事先生成ID,然后再在INSERT语句中重用它。

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

答案 1 :(得分:1)

我有与主题启动器相同的任务。感谢 @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.如果您使用raw(16),那么表中的字段为char(32),用于高效存储和较小的索引大小。

当我尝试将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"));

所有网络控制器都会获得如下代码:

025131763FB19522E050010A106D11E9

没有{-}字符(如果您记得的话,UUID的常规表示为{a-b-c-d-x-y})。此表示已经URL编码干净且安全。您不需要为PropertyEditor类型实施ConvertorString

@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,

答案 2 :(得分:0)

我认为您可以通过将生成器设置为本机来实现。我不确定如何在Hibernate中实现它,但在NHibernate中你会在XML中做这样的事情:

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