【问题标题】:Problems mapping UUID in JPA/hibernate在 JPA/hibernate 中映射 UUID 的问题
【发布时间】:2011-05-19 19:33:08
【问题描述】:

根据文档,hibernate 3.6 应该支持 java.util.UUID 类型。但是当我像这样映射它时:

@Id protected UUID uuid;

我得到以下异常:

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

我知道堆栈跟踪问题不是很流行,但这是一个非常特定于休眠的问题,我在谷歌上找不到任何东西:)

谢谢

【问题讨论】:

  • 您使用的是什么 rdbms,您使用的是哪个 jdbc 驱动程序版本?
  • MySQL 5.1.47 和 mysql-connector 5.1.13
  • 实际上,没有堆栈跟踪的问题并不受欢迎。

标签: java hibernate jpa uuid


【解决方案1】:

使用代码示例扩展 Mike Lively 的答案并参考 Oracle。

我在使用 OracleDialect (Oracle10gDialect) 时遇到了这个问题。向 UUID 字段添加注释 @Type 为我修复了它。

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

注意:在该字段上也使用了 TwoWayStringBridge,使用 @FieldBridge 注释。

注意:type="uuid-binary" 不起作用;得到相同的未知类型错误。

【讨论】:

  • 是否有任何全局属性可以将此设置为所有 java.util.UUID 到 uuid-char 的默认映射,这样我就不必为使用 UUID 的每个实体键入此注释? (我还想避免在我的代码中使用特定于休眠的注释,并将其全部保留为 javax.persistance。
  • 是的!请参阅下面的 jpkrohling 的答案。只需自定义您的数据库方言并在其构造函数中注册列类型。
  • 受这个答案的启发,我让 Spring JPA 与 Oracle DB(在 Kotlin 中)一起工作:@Column(name = "uuid") @Type(type="uuid-char") var uuid: UUID? = null. 使用它时,val x = UUID.fromString("00a023b3-1357-3070-a661-72a09f8ccdb2") 从 str 转换为 uuid。在 Oracle 数据库上:ALTER TABLE ADD UUID RAW(16) default SYS_GUID() NOT NULL.
  • 谢谢@Emily!很高兴这对您有所启发。
  • 这是救命稻草。谢谢
【解决方案2】:

UUID 是 3.6 中添加的基本类型。但是,默认情况下,它会转换为 JDBC 二进制类型,这似乎会导致 mysql 出现问题。您可以通过显式指定 uuid-char 作为类型来覆盖此行为。

【讨论】:

  • 好的,如果我想用二进制 (16) 写故事怎么办?
  • 如果是这种情况,那么您将想做类似于partenon 的回答的事情。听起来好像从您的评论到他的回答,无论出于何种原因,16 位都是不够的。这可能是 mysql 的 jdbc 驱动程序中的映射是如何工作的。我需要做更多的研究才能提供细节。如果您想使用它来查看发生了什么,请尝试将其升级到 binary(32) 并查看放入数据库中的内容。
【解决方案3】:
Caused by: org.hibernate.MappingException: No Dialect mapping for JDBC type: -2

这意味着 Hibernate 将 UUID 映射为 BINARY[1],但没有 MySQL 方言将 BINARY 映射到 MySQL 数据类型。看看 MySQL 的 Dialect 层次结构:

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

将它们与这个进行比较(搜索 BINARY 映射): https://github.com/hibernate/hibernate-core/blob/master/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java

可能是 Hibernate 中的一个错误,因为我确实在 MySQL 文档中看到了 BINARY 数据类型,但您可能想在 Hibernate 的 JIRA 中进行一些搜索,看看是否有任何原因这没有映射。

如果你愿意测试,你可以只继承 MySQL5InnoDBDialect(如果你使用 InnoDB),并将其用于构造函数:

registerColumnType( Types.BINARY, "binary" );

所以,这就是 String 可以正常工作的原因,而 java.util.UUID 却不行。

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

【讨论】:

  • 我这样做并得到了这个:com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'uuid' at row 1
  • 我会阅读有关这方面的 MySQL 文档,并尝试想出一种方法来将此 UUID 二进制数据存储到 MySQL 列中,数据类型为仅使用 JDBC 的二进制。如果您能够使用纯 JDBC 做到这一点,那么 Hibernate 也应该能够做到。在这种情况下,请在 Hibernate JIRA 中打开一个尽可能详细的问题(如果您附加测试用例,则可以加分)。我很确定 Hibernate 的优秀人员会接受它,并且很高兴得到您的贡献。
【解决方案4】:

使用带有 InnoDB 表的 Hibernate 4 和 MySQL 5.5,我能够将 UUID 列按原样存储为 BINARY(16)(无需配置或自定义类型)。我没有将其用作实体 ID,而是使用 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                |
| ...            |               |      |     |                     |
+----------------+---------------+------+-----+---------------------+

【讨论】:

  • 如何将值作为 UUID 取回?
  • Hibernate 自动进行映射。您的代码与我添加到答案中的代码相符吗?
  • 这是 Hibernate 4 及更高版本的最佳答案!
  • 2020年依然是完美答案
【解决方案5】:

不要使用类型UUID,因为您需要自定义类型来处理它。

使用String。见this post。这是实现它的一种方式。

另一种方法是使用 hibernate 内置的 UUID 生成器。你需要 @GeneratedValue 和一个名为 hibernate-uuid 的生成器

【讨论】:

  • 使用String查询和存储效率不是很高。另外,hibernate 3.6 应该支持 UUID 类型的映射吗?还是我需要将它与@generatedvalue 结合使用才能正常工作?
  • 如果不是字符串,你将如何将它存储在数据库中?
  • 谢谢,这对我尝试连接到 MS SQL 服务器很有用。
  • 使用 UUID 而不是 String 有一个关键优势,您无需担心 id 的大小写。在我的应用程序中,ID 来自不同的来源,因此有时情况可能会有所不同,这在比较它们时会造成一些麻烦。
  • 我用的是String,这里stackoverflow.com/questions/41651681的问题发生在我身上,所以不是解决办法。
【解决方案6】:

当我在寻找使用 JDBC 的 UUID 映射时,Google 搜索将我带到了这篇文章,所以如果你不介意,我会发布我的经验。

在我的项目中,我在单元测试中使用 H2 在 H2 和 MySql 之间切换。 H2 原生支持 UUID 类型。但是mysql java连接器没有。所以我唯一的选择是在我不喜欢的客户端代码中将BINARY(16) 转换为UUID

因此,我修补了官方 mysql java 连接器以将 UUID 视为 BINARY(16)。我知道这有点老套,但对我有用。

如果你想尝试一下,我在 github 上发布了它:http://goo.gl/NIhNi

【讨论】:

  • 你的链接是 404。
  • @BugsBuggy 是的,很抱歉。我认为 2020 年没有人使用 JPA,所以我删除了回购。我推荐使用Jdbi
猜你喜欢
  • 2014-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多