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

Posted

技术标签:

【中文标题】在不同情况下使用不同的 Hibernate 用户类型【英文标题】:Using Different Hibernate User Types in Different Situations 【发布时间】:2010-11-03 16:16:45 【问题描述】:

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

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

我希望能够在 Hibernate 中使用 Postgres 的原生 UUID 类型,并在其字符串表示中使用 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;

而且效果很好。但我需要的是能够将注释的“com.xxx.UUIDStringType”部分换出 XML 或属性文件,无需重新编译即可更改。

有什么想法吗?

【问题讨论】:

【参考方案1】:

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

    binary-uuid : 将 UUID 存储为二进制 uuid-char :将 UUID 存储为字符序列 pg-uuid :使用原生 Postgres UUID 类型

这些类型是默认注册的,可以用@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 类型在两种环境中都可用。

【讨论】:

我没有看到 addTypeOverride 在该课程中被调用。我正在使用休眠 5。 似乎是休眠中的一个已知问题。 github.com/spring-projects/spring-data-jpa/issues/… 上述使用@Type("pg-uuid") 的解决方案对我不起作用。【参考方案2】:

为了避免 UUID 类型之间的问题而不指定 @Type 注释(这基本上意味着当你想从 postgres 更改为 mysql 或其他方式时,你必须调整所有注释......)我正在使用package-info.java 与该包上的休眠 @TypeDef 注释。

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

只需在您的domain 包中创建两个package-info.java

确保 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;

希望对你有帮助

【讨论】:

我对此有困难,我认为是因为 Eclipse 如何使用类路径。但是我能够通过将我的“生产”包信息放在更高级别的命名空间中并将我的“测试”包信息放在较低级别的名称空间中来使其工作【参考方案3】:

嘿,对于那些在 Hibernate 4 中寻求解决方案的人(因为 Dialect#addTypeOverride 方法不再可用),我找到了一个,基于this Steve Ebersole's comment

你必须建立一个像这样的自定义用户类型:

public class UUIDStringCustomType extends AbstractSingleColumnStandardBasicType 

    public UUIDStringCustomType() 
        super(VarcharTypeDescriptor.INSTANCE, UUIDTypeDescriptor.INSTANCE);
    

    @Override
    public String getName() 
        return "pg-uuid";
    


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

public class CustomHsqlDialect extends HSQLDialect 


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


然后你可以将@Type(type="pg-uuid") 与两个数据库一起使用。

希望对某人有所帮助...

【讨论】:

如何将 HSQLDialect 链接到 JPA? 您必须在 hibernate(或任何实现)配置文件中定义属性: hibernate.dialect 。在这里,您使用他的类路径指定新的方言 CustomHsqlDialect。希望你仍然感兴趣... spring.jpa.properties.hibernate.dialect = com.yourpackage.etc.CustomHsqlDialect【参考方案4】:

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

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

【讨论】:

谢谢伙计..你是一个救生员。策略模式就像一个魅力。

以上是关于在不同情况下使用不同的 Hibernate 用户类型的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate - JPA 在不同的情况下生成具有相同名称的重复表

Hibernate 已返回零结果,但本机 sql 返回不同

Hibernate中@Embedded和@Embeddable注解

如何使用 hibernate/jpa 注释将一个类映射到不同的表

如何在没有 !important 的情况下使用不同的类覆盖 css

如何使用不同类型的项目制作 RecyclerView? [复制]