Java Hibernate 支持 Postgresql UUID?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4495233/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 18:02:29  来源:igfitidea点击:

Postgresql UUID supported by Hibernate?

javahibernatepostgresqlormhibernate-mapping

提问by forker

I can't get Hibernate working with java.util.UUID for PostgreSQL.

我无法让 Hibernate 使用 java.util.UUID for PostgreSQL。

Here is the mapping using javax.persistence.* annotations:

这是使用 javax.persistence.* 注释的映射:

private UUID itemUuid;

@Column(name="item_uuid",columnDefinition="uuid NOT NULL")
public UUID getItemUuid() {
    return itemUuid;
}

public void setItemUuid(UUID itemUuid) {
    this.itemUuid = itemUuid;
}

When persisting a transient object I get a SQLGrammarException:

当持久化一个瞬态对象时,我得到一个 SQLGrammarException:

column "item_uuid" is of type uuid but expression is of type bytea at character 149

PostgreSQL version is 8.4.4
JDBC driver - 8.4.4-702 (also tried 9.0 - same thing)
Hibernate version is 3.6, main configuration properties:

PostgreSQL 版本是 8.4.4
JDBC 驱动程序 - 8.4.4-702(也试过 9.0 - 同样的事情)
Hibernate 版本是 3.6,主要配置属性:

<property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
<property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
<property name="hibernate.connection.url">jdbc:postgresql://192.168.1.1/db_test</property>

采纳答案by Robyn P

This can be solved by adding the following annotation to the UUID:

这可以通过向 UUID 添加以下注释来解决:

import org.hibernate.annotations.Type;
...
@Type(type="pg-uuid")
private java.util.UUID itemUuid;

As to why Hibernate doesn't just make this the default setting, I couldn't tell you...

至于为什么 Hibernate 不只是将其设为默认设置,我无法告诉您...

UPDATE: There still seem to be issues using the createNativeQuery method to open objects that have UUID fields. Fortunately, the createQuery method so far has worked fine for me.

更新:使用 createNativeQuery 方法打开具有 UUID 字段的对象似乎仍然存在问题。幸运的是,到目前为止,createQuery 方法对我来说效果很好。

回答by Danubian Sailor

You try to persist object of type UUID, which is not hibernate-annotated entity. So the hibernate wants to serialize it to byte array (blob type). This is why you get this message 'expression of type bytea'.

您尝试保留 UUID 类型的对象,该对象不是带有休眠注释的实体。所以hibernate想要将它序列化为字节数组(blob类型)。这就是为什么您会收到此消息“bytea 类型的表达式”。

You can either store UUID as blobs in database (not elegant), or provide your custom serializer (much work) or manually convert that object. UUID class has methods fromString and toString, so I would store it as String.

您可以将 UUID 作为 blob 存储在数据库中(不优雅),或者提供您的自定义序列化程序(大量工作)或手动转换该对象。UUID 类具有 fromString 和 toString 方法,因此我将其存储为 String。

回答by Tomasz

Solution for someone who don't use JPA.

不使用 JPA 的人的解决方案。

Before:

前:

<property name="testId" >
        <column name="test_id"  sql-type="uuid"  not-null="true"/>
</property>

After:

后:

<property name="testId" column="test_id" type="org.hibernate.type.PostgresUUIDType">
</property>

回答by Pieter van Ginkel

As others mentioned, the solution to this issue is to add a @Type(type = "pg-uuid")annotation. However, this type is not compatible with UUID types of other vendors, so this ties your Hibernate classes to Postgres. To work around this, it is possible to insert this annotation at runtime. The below works for Hibernate 4.3.7.

正如其他人提到的,这个问题的解决方案是添加@Type(type = "pg-uuid")注释。但是,这种类型与其他供应商的 UUID 类型不兼容,因此这会将您的 Hibernate 类与 Postgres 联系起来。要解决此问题,可以在运行时插入此注释。以下适用于 Hibernate 4.3.7。

First, you need to insert a custom metadata provider to insert the annotations. Do this as the first step after creating an instance of the Configurationclass:

首先,您需要插入自定义元数据提供程序以插入注释。在创建Configuration类的实例后,第一步执行此操作:

// Perform some test to verify that the current database is Postgres.
if (connectionString.startsWith("jdbc:postgresql:")) {
    // Replace the metadata provider with our custom metadata provider.
    MetadataProviderInjector reflectionManager = MetadataProviderInjector)cfg.getReflectionManager();
    reflectionManager.setMetadataProvider(new UUIDTypeInsertingMetadataProvider(reflectionManager.getMetadataProvider()));
}

This custom metadata provider finds fields and methods of type UUID. If it finds one, it inserts an instance of the org.hibernate.annotations.Typeannotation stating that the type should be "pg-uuid":

此自定义元数据提供程序查找类型为 的字段和方法UUID。如果找到,它会插入一个org.hibernate.annotations.Type注解实例,说明类型应该是"pg-uuid"

package nl.gmt.data;

import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.common.reflection.AnnotationReader;
import org.hibernate.annotations.common.reflection.MetadataProvider;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

class UUIDTypeInsertingMetadataProvider implements MetadataProvider {
    private final Map<AnnotatedElement, AnnotationReader> cache = new HashMap<>();
    private final MetadataProvider delegate;

    public UUIDTypeInsertingMetadataProvider(MetadataProvider delegate) {
        this.delegate = delegate;
    }

    @Override
    public Map<Object, Object> getDefaults() {
        return delegate.getDefaults();
    }

    @Override
    public AnnotationReader getAnnotationReader(AnnotatedElement annotatedElement) {
        // This method is called a lot of times on the same element, so annotation
        // readers are cached. We only cache our readers because the provider
        // we delegate to also caches them.

        AnnotationReader reader = cache.get(annotatedElement);
        if (reader != null) {
            return reader;
        }

        reader = delegate.getAnnotationReader(annotatedElement);

        // If this element is a method that returns a UUID, or a field of type UUID,
        // wrap the returned reader in a new reader that inserts the "pg-uuid" Type
        // annotation.

        boolean isUuid = false;
        if (annotatedElement instanceof Method) {
            isUuid = ((Method)annotatedElement).getReturnType() == UUID.class;
        } else if (annotatedElement instanceof Field) {
            isUuid = ((Field)annotatedElement).getType() == UUID.class;
        }

        if (isUuid) {
            reader = new UUIDTypeInserter(reader);
            cache.put(annotatedElement, reader);
        }

        return reader;
    }

    private static class UUIDTypeInserter implements AnnotationReader {
        private static final Type INSTANCE = new Type() {
            @Override
            public Class<? extends Annotation> annotationType() {
                return Type.class;
            }

            @Override
            public String type() {
                return "pg-uuid";
            }

            @Override
            public Parameter[] parameters() {
                return new Parameter[0];
            }
        };

        private final AnnotationReader delegate;

        public UUIDTypeInserter(AnnotationReader delegate) {
            this.delegate = delegate;
        }

        @Override
        @SuppressWarnings("unchecked")
        public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
            if (annotationType == Type.class) {
                return (T)INSTANCE;
            }

            return delegate.getAnnotation(annotationType);
        }

        @Override
        public <T extends Annotation> boolean isAnnotationPresent(Class<T> annotationType) {
            return annotationType == Type.class || delegate.isAnnotationPresent(annotationType);
        }

        @Override
        public Annotation[] getAnnotations() {
            Annotation[] annotations = delegate.getAnnotations();
            Annotation[] result = Arrays.copyOf(annotations, annotations.length + 1);
            result[result.length - 1] = INSTANCE;
            return result;
        }
    }
}

回答by wrathtoliar

Now you can also use the UUID class provided by java.util.UUID which gets mapped to uuid datatype of Postgres by Hibernate without any conversions required while reading/writing from the database.

现在,您还可以使用 java.util.UUID 提供的 UUID 类,该类通过 Hibernate 映射到 Postgres 的 uuid 数据类型,而无需在从数据库读取/写入时进行任何转换。

  @Id
  @GeneratedValue
  private UUID id;

The generated value is auto by default this lets your JVM define the UUID. This also allows hibernate to use the batch insert optimisation.

默认情况下生成的值是 auto 这让您的 JVM 定义 UUID。这也允许 hibernate 使用批量插入优化。

You can configure the database to set the UUID value. More information can be found here https://vladmihalcea.com/uuid-identifier-jpa-hibernate/

您可以配置数据库以设置 UUID 值。更多信息可以在这里找到https://vladmihalcea.com/uuid-identifier-jpa-hibernate/