在不同情况下使用不同的Hibernate用户类型

时间:2009-06-17 13:52:41

标签: java hibernate jpa annotations hsqldb

我正在使用Hibernate + JPA作为我的ORM解决方案。

我使用HSQL进行单元测试,将PostgreSQL用作真正的数据库。

我希望能够将Postgres的本地UUID类型与Hibernate一起使用,并在其字符串表示中使用UUID和HSQL进行单元测试(因为HSQL没有UUID类型)。

我正在为Postgres和HSQL单元测试使用具有不同配置的持久性XML。

以下是我如何让Hibernate“看到”我的自定义UserType:

@Id
@Column(name="UUID", length=36)
@org.hibernate.annotations.Type(type="com.xxx.UUIDStringType")
public UUID getUUID() {
    return uuid;
}


public void setUUID(UUID uuid) {
    this.uuid = uuid;
}

这很有效。但我需要的是能够在XML中替换注释的“com.xxx.UUIDStringType”部分,或者从可以在不重新编译的情况下更改的属性文件。

有什么想法吗?

4 个答案:

答案 0 :(得分:9)

Hy,对于那些在Hibernate 4中寻求解决方案的人来说(因为Dialect#addTypeOverride方法不再可用),我在this Steve Ebersole's comment

找到了一个,

您必须构建类似这样的自定义用户类型:

public class CustomHsqlDialect extends HSQLDialect {


    @Override
    public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
        super.contributeTypes(typeContributions,serviceRegistry);
        typeContributions.contributeType(new UUIDStringCustomType());
    }

}

要将它绑定到HSQLDB方言,您必须构建一个覆盖Dialect#contributionTypes方法的自定义方言,如下所示:

funcs = [ lambda: i for i in range(3) ]
print(funcs[0]())
=> 2  #??
print(funcs[1]())
=> 2  #??
print(funcs[2]())
=> 2

然后你可以在两个数据库中使用@Type(type =“pg-uuid”)。

希望它会帮助某人......

答案 1 :(得分:4)

这个问题很老了,已经回答了很长时间,但我最近发现自己处于同样的情况并找到了一个很好的解决方案。对于初学者,我发现Hibernate有三种不同的内置UUID类型实现:

  1. binary-uuid:将UUID存储为二进制文件
  2. uuid-char:将UUID存储为字符序列
  3. pg-uuid:使用本机Postgres UUID类型
  4. 这些类型是默认注册的,可以为具有@Type注释的给定字段指定,例如

    @Column
    @Type(type = "pg-uuid")
    private UUID myUuidField;
    

    还有 一种覆盖Dialect中默认类型的机制。因此,如果最终部署是与Postgres数据库通信,但是单元测试使用HSQL,则可以通过编写自定义方言来覆盖pg-uuid类型来读取/写入字符数据:

    public class CustomHSQLDialect extends HSQLDialect {
    
        public CustomHSQLDialect() {
            super();
    
            // overrides the default implementation of "pg-uuid" to replace it
            // with varchar-based storage.
            addTypeOverride(new UUIDCharType() {
                @Override
                public String getName() {
                    return "pg-uuid";
                }
            });
        }
    }
    

    现在只需插入自定义方言,两种环境都可以使用pg-uuid类型。

答案 2 :(得分:3)

为了避免UUID类型之间的问题而没有指定@Type注释(这基本上意味着当你想要从postgres更改为mysql或者反过来时你必须调整所有注释...)I&#39 ; m使用package-info.java在该包装上使用hibernates @TypeDef注释。

以下是您的应用程序的示例设置:
假设module/src/main/java/app.package.domain包含您的实体。并且您的测试存储在module/src/test/java/app.package中。

只需在package-info.java个包中创建两个domain即可。

  

确保package-info文件始终位于同一个包中(用于测试和生产)。请参阅以下示例:

src/main/java
  app
    package
      domain
        package-info.java 

src/test/java
  app
    package
      domain
        package-info.java 

您的制作package-info.java的内容应如下所示(Postgres):

@TypeDef(
  name = "pg-uuid",
  defaultForType = UUID.class,
  typeClass = PostgresUUIDType.class
)
package app.package.domain;

import org.hibernate.annotations.TypeDef;
import org.hibernate.type.PostgresUUIDType;

import java.util.UUID;

这就是你如何测试"配置"应该看起来像(H2):

@TypeDef(
  name = "uuid-char",
  defaultForType = UUID.class,
  typeClass = UUIDCharType.class
)
package app.package.domain;

import org.hibernate.annotations.TypeDef;
import org.hibernate.type.UUIDCharType;

import java.util.UUID;

希望有所帮助

答案 3 :(得分:2)

也许您可以在用户类型中构建一些智能,以根据数据库功能执行正确的操作。 Hibernate本身采用与其“本机”ID生成器类似的方法,根据您使用的数据库类型,它的行为会有所不同。这样的方法消除了在运行时切换映射的需要。

例如,您可以为每个数据库创建一个strategy类。然后在您的用户类型类中,检测您第一次调用时连接到的数据库,为该数据库实例化适当的策略,然后将所有调用委托给策略对象。