web-dev-qa-db-fra.com

Problèmes de mappage des UUID dans JPA/hibernate

Selon la documentation, hibernate 3.6 devrait prendre en charge le type Java.util.UUID. Mais quand je mappe comme ça:

@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 il s’agit d’un problème très spécifique à la veille prolongée et je n’ai rien trouvé sur Google :)

Merci

23
Piotr

L'UUID était un type de base ajouté en 3.6. Cependant, par défaut, il se traduit par un type binaire JDBC qui semble poser problème à mysql. Vous pouvez remplacer ce comportement en spécifiant explicitement uuid-char en tant que type.

27
Mike Lively

Extension de la réponse de Mike Lively avec un exemple de code et référence à Oracle également.

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;

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

Remarque: type = "uuid-binary" n'a pas fonctionné. obtenu le même, erreur de type inconnu.

34
Barett
Caused by: org.hibernate.MappingException: No Dialect mapping for JDBC type: -2

Cela signifie que l'UUID est mappé en tant que BINARY [1] par Hibernate, mais aucun dialecte MySQL ne mappe BINARY à un type de données MySQL. Jetez un coup d’œil à la hiérarchie Dialect 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 (recherchez la cartographie BINARY): https://github.com/hibernate/hibernate-core/blob/master/hibernate-core/src/main/Java/org/hibernate/ dialect/HSQLDialect.Java

Ceci peut être un bogue dans Hibernate, car je vois le type de données BINARY disponible dans la documentation MySQL, mais vous souhaiterez peut-être effectuer une recherche dans la JIRA d'Hibernate pour voir s'il existe une quelconque raison pour laquelle cela n'est pas mappé.

Si vous êtes prêt à tester, vous pouvez simplement créer une sous-classe MySQL5InnoDBDialect (si vous utilisez InnoDB) et l’utiliser pour le constructeur:

registerColumnType( Types.BINARY, "binary" );

C'est donc la raison pour laquelle la chaîne fonctionne, mais pas Java.util.UUID.

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

9
jpkrohling

En utilisant Hibernate 4 et MySQL 5.5 avec une table InnoDB, j'ai pu stocker une colonne UUID sous la forme BINARY(16) telle quelle (aucune configuration ni type personnalisé requis). Je n'utilise pas cela comme ID d'entité et je crée la valeur manuellement à l'aide de 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
David Harkness

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 le mettre en œuvre. 

Une autre méthode consiste à utiliser le générateur UUID intégré au mode veille prolongée. Vous aurez besoin de @GeneratedValue avec un générateur nommé hibernate-uuid

4
Bozho

La recherche Google m'a conduit à ce message alors que je cherchais la cartographie UUID avec JDBC, je vais donc publier mon expérience si cela ne vous dérange pas.

Sur mon projet, je bascule entre H2 et MySql en utilisant H2 en test unitaire. H2 supporte nativement le type UUID. Mais le connecteur Java mysql ne le fait pas. Ainsi, ma seule option est de convertir BINARY(16) en UUID en code client, ce que je n’aime pas.

En conséquence, j'ai corrigé le connecteur Java officiel MySQL pour traiter l'UUID comme étant BINARY (16). Je sais que c'est un peu hacky mais ça marche pour moi.

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

0
expert