Problèmes de mappage de L'UUID dans JPA / hibernate

Selon la documentation, hibernate 3.6 devrait avoir un support pour java.util.Type UUID. Mais quand je le mappe comme:

@Id protected UUID uuid;

Je reçois l'exception suivante:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [test-applicationContext.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: persistenceUnit] Unable to build EntityManagerFactory
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1420) ~[spring-beans-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519) ~[spring-beans-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) ~[spring-beans-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291) ~[spring-beans-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288) ~[spring-beans-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190) ~[spring-beans-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findDefaultEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:529) ~[spring-orm-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:495) ~[spring-orm-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.resolveEntityManager(PersistenceAnnotationBeanPostProcessor.java:656) ~[spring-orm-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.getResourceToInject(PersistenceAnnotationBeanPostProcessor.java:629) ~[spring-orm-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:147) ~[spring-beans-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:84) ~[spring-beans-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:338) ~[spring-orm-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    ... 51 common frames omitted
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: persistenceUnit] Unable to build EntityManagerFactory
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:911) ~[hibernate-entitymanager-3.6.0.Final.jar:3.6.0.Final]
    at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:74) ~[hibernate-entitymanager-3.6.0.Final.jar:3.6.0.Final]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:225) ~[spring-orm-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:308) ~[spring-orm-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1477) ~[spring-beans-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1417) ~[spring-beans-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    ... 64 common frames omitted
Caused by: org.hibernate.MappingException: No Dialect mapping for JDBC type: -2
    at org.hibernate.dialect.TypeNames.get(TypeNames.java:78) ~[hibernate-core-3.6.0.Final.jar:3.6.0.Final]
    at org.hibernate.dialect.TypeNames.get(TypeNames.java:103) ~[hibernate-core-3.6.0.Final.jar:3.6.0.Final]
    at org.hibernate.dialect.Dialect.getTypeName(Dialect.java:249) ~[hibernate-core-3.6.0.Final.jar:3.6.0.Final]
    at org.hibernate.mapping.Column.getSqlType(Column.java:208) ~[hibernate-core-3.6.0.Final.jar:3.6.0.Final]
    at org.hibernate.mapping.Table.sqlTemporaryTableCreateString(Table.java:371) ~[hibernate-core-3.6.0.Final.jar:3.6.0.Final]
    at org.hibernate.mapping.PersistentClass.prepareTemporaryTables(PersistentClass.java:765) ~[hibernate-core-3.6.0.Final.jar:3.6.0.Final]
    at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:270) ~[hibernate-core-3.6.0.Final.jar:3.6.0.Final]
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1842) ~[hibernate-core-3.6.0.Final.jar:3.6.0.Final]
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:902) ~[hibernate-entitymanager-3.6.0.Final.jar:3.6.0.Final]
    ... 69 common frames omitted

Je sais que les questions avec des traces de pile ne sont pas très populaires mais c'est un problème très spécifique à hibernate et j'ai été incapable de trouver quoi que ce soit sur google:)

Merci

23
demandé sur Bozho 2010-12-03 18:16:20

6 réponses

UUID était un type de base ajouté dans 3.6. Cependant, par défaut, il se traduit par un type binaire JDBC qui semble causer des problèmes pour mysql. Vous pouvez remplacer ce comportement en spécifiant explicitement uuid-char comme type.

24
répondu Mike Lively 2010-12-03 15:55:23

Étendre la réponse de Mike Lively avec un exemple de code et se référant à Oracle aussi.

J'ai eu ce problème avec OracleDialect (Oracle10gDialect). L'ajout d'une annotation @Type au champ UUID l'a corrigé pour moi.

@Id
@Type(type="uuid-char")
private UUID id;

Note: également utilisé un TwoWayStringBridge sur ce champ, en utilisant l'annotation @ FieldBridge.

Note: type = "uuid-binary" n'a pas fonctionné; a obtenu la même erreur de type inconnu.

30
répondu Barett 2011-01-27 23:56:53
Caused by: org.hibernate.MappingException: No Dialect mapping for JDBC type: -2

Cela signifie que UUID est mappé en tant que binaire [1] par Hibernate, mais aucun dialecte MySQL ne mappe binaire à un type de données MySQL. Jetez un oeil à la hiérarchie des dialectes pour MySQL:

Https://github.com/hibernate/hibernate-core/blob/master/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java

Https://github.com/hibernate/hibernate-core/blob/master/hibernate-core/src/main/java/org/hibernate/dialect/MySQL5Dialect.java

Https://github.com/hibernate/hibernate-core/blob/master/hibernate-core/src/main/java/org/hibernate/dialect/MySQL5InnoDBDialect.java

Comparez-les avec celui-ci (recherche du mappage binaire): https://github.com/hibernate/hibernate-core/blob/master/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java

Ce peut être un bug dans Hibernate, car je vois le type de données binaires disponible dans la documentation MySQL, mais vous pouvez faire une recherche dans le JIRA D'Hibernate pour voir s'il y a une raison pour laquelle cela n'est pas mappé.

Si vous êtes prêt à tester, vous pouvez simplement sous-classer MySQL5InnoDBDialect (si vous êtes en utilisant InnoDB), et utilisez ceci pour le constructeur:

registerColumnType( Types.BINARY, "binary" );

Donc, c'est la raison pour laquelle la chaîne fonctionne, mais java.util.L'UUID est pas.

1 - http://download.oracle.com/javase/6/docs/api/constant-values.html#java.sql.Types.BINARY

7
répondu jpkrohling 2010-12-03 16:33:04

En utilisant Hibernate 4 et MySQL 5.5 avec une table InnoDB, j'ai pu stocker une colonne UUID comme BINARY(16) telle quelle (aucune configuration ou type personnalisé requis). Je ne l'utilise pas comme ID d'entité et je crée la valeur manuellement en utilisant UUID.randomUUID().

@Entity
@Table(name = "post")
public class PostModel implements Serializable
{
    ...
    @Column(name = "uuid", nullable = false, updatable = false)
    private UUID uuid;
    ...
}

> desc post;
+----------------+---------------+------+-----+---------------------+
| Field          | Type          | Null | Key | Default             |
+----------------+---------------+------+-----+---------------------+
| ...            |               |      |     |                     |
| uuid           | binary(16)    | YES  | UNI | NULL                |
| ...            |               |      |     |                     |
+----------------+---------------+------+-----+---------------------+
7
répondu David Harkness 2014-11-05 19:38:14

N'utilisez pas le type UUID, car vous auriez besoin d'un type personnalisé pour le gérer.

Utilisez String. Voir ce post. C'est une façon de la mettre en œuvre.

Une autre façon est d'utiliser le générateur UUID construit dans hibernate. Vous auriez besoin de @GeneratedValue avec un générateur nommé hibernate-uuid

3
répondu Bozho 2010-12-03 15:47:50

La recherche Google m'a conduit à ce post quand je cherchais un mappage UUID avec JDBC, donc je posterai mon expérience si cela ne vous dérange pas.

Sur mon projet, je passe entre H2 et MySql en utilisant H2 dans les tests unitaires. H2 supporte nativement le type UUID. Donc, ma seule option est de convertir BINARY(16) en UUID dans le code client que je n'aime pas.

En conséquence, j'ai patché le connecteur Java mysql officiel pour traiter UUID comme binaire (16). Je sais que c'est un peu hacky mais fonctionne pour je.

Si vous voulez l'essayer je l'ai posté sur github: http://goo.gl/NIhNi

0
répondu expert 2013-06-07 08:02:41