Postgresql UUID supported by Hibernate?

匿名 (未验证) 提交于 2019-12-03 08:30:34

问题:

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

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

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:

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:

org.hibernate.dialect.PostgreSQLDialectorg.postgresql.Driverjdbc:postgresql://192.168.1.1/db_test

回答1:

This can be solved by adding the following annotation to the 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...

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.



回答2:

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'.

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.



回答3:

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.

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 Configuration class:

// 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.Type annotation stating that the type should be "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 cache = new HashMap();     private final MetadataProvider delegate;      public UUIDTypeInsertingMetadataProvider(MetadataProvider delegate) {         this.delegate = delegate;     }      @Override     public Map 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 getAnnotation(Class annotationType) {             if (annotationType == Type.class) {                 return (T)INSTANCE;             }              return delegate.getAnnotation(annotationType);         }          @Override         public  boolean isAnnotationPresent(Class 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;         }     } } 


回答4:

Solution for someone who don't use JPA.

Before:

After:



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!