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
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.
É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.
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:
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
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 |
| ... | | | | |
+----------------+---------------+------+-----+---------------------+
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
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