20

PostgreSQL の java.util.UUID で Hibernate を動作させることができません。

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;
}

一時オブジェクトを永続化すると、SQLGrammarException が発生します。

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

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>
4

6 に答える 6

40

これは、UUIDに次の注釈を追加することで解決できます。

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

Hibernateがこれをデフォルト設定にしない理由については、私はあなたに言うことができませんでした...

更新:createNativeQueryメソッドを使用してUUIDフィールドを持つオブジェクトを開く際にまだ問題があるようです。幸い、これまでのcreateQueryメソッドは問題なく機能しました。

于 2011-09-20T01:04:20.577 に答える
6

休止状態で注釈が付けられたエンティティではないタイプ UUID のオブジェクトを永続化しようとしています。そのため、休止状態はそれをバイト配列 (blob タイプ) にシリアライズしたいと考えています。これが、'expression of type bytea' というメッセージを受け取る理由です。

UUID を blob としてデータベースに格納するか (エレガントではありません)、カスタム シリアライザーを提供するか (多くの作業が必要です)、そのオブジェクトを手動で変換することができます。UUID クラスには fromString と toString のメソッドがあるので、String として格納します。

于 2010-12-21T13:23:05.853 に答える
3

@Type(type = "pg-uuid")他の人が述べたように、この問題の解決策は注釈を追加することです。ただし、このタイプは他のベンダーの UUID タイプと互換性がないため、Hibernate クラスを Postgres に関連付けます。これを回避するために、実行時にこの注釈を挿入することができます。以下は、Hibernate 4.3.7 で機能します。

最初に、注釈を挿入するカスタム メタデータ プロバイダーを挿入する必要があります。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()));
}

このカスタム メタデータ プロバイダーは、 type のフィールドとメソッドを検索します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;
        }
    }
}
于 2015-06-25T09:35:52.587 に答える
0

JPAを使用していない人向けのソリューション。

前:

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

後:

<property name="testId" column="test_id" type="org.hibernate.type.PostgresUUIDType">
</property>
于 2014-10-09T08:09:18.490 に答える
0

postgres で Sprint Data と jsonb を使用しているときに、同様の問題が発生しました。解決策をありがとうSri

モデルでは、置き換え

@Type(type="pg-uuid")

@Type(type="org.hibernate.type.PostgresUUIDType")

@SpringBootTest で JUnit テストを実行する問題を解決しました。

エンティティ (Kotlin) での例:

@Type(type="org.hibernate.type.PostgresUUIDType")
@Column(
    nullable = false,
    unique = true,
    updatable = false,
    columnDefinition = "CHAR(36)"
)
var uuid: UUID = UUID.randomUUID()
于 2021-09-10T11:15:45.343 に答える