通过使用 MySQL 的 DataJpaTest 存储库测试,Hibernate 不会在 H2 DB 中将用户设置为自动增量
Posted
技术标签:
【中文标题】通过使用 MySQL 的 DataJpaTest 存储库测试,Hibernate 不会在 H2 DB 中将用户设置为自动增量【英文标题】:With DataJpaTest Repository Tests using MySQL, Hibernate doesn't set User to auto-increment in H2 DB 【发布时间】:2019-07-12 18:52:28 【问题描述】:我正在尝试使用 DataJpaTest 测试我的 Spring Boot 存储库。我使用的是 mysql,所以我所有的模型都使用 IDENTITY 来生成 id:
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
但正如您从下面的屏幕截图中看到的那样,当我运行测试时,Hibernate 为除用户和属性之外的所有模型的 id 设置“默认生成为身份”:
这使得我无法在我的测试中创建用户(或属性),因为 GenerationType.IDENTITY 集总是在将 id 发送到数据库之前将其设置为 null,这会导致以下错误:
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
有人知道为什么会这样吗?而且,当然,比为什么我能做些什么来修复它更重要? :)
更新 为了简化问题并为我尝试过的不同事情提供不同的错误......
我的 DataJpaTests 正在使用 H2,我猜它是从代码中自动生成 db 结构。我真正的数据库是MYSQL,它是在一个单独的项目中生成的。
场景 1:
当我将 GenerationType 设置为 IDENTITY 时,实时数据库可以工作,但测试数据库给了我could not execute statement; SQL [n/a]; constraint [null]
。
场景 2:
当我将 GenerationType 设置为 AUTO 时,测试数据库可以工作,但实时数据库给了我Table 'tablename.hibernate_sequence' doesn't exist
。
场景 3: 试图使 MYSQL 与 GenerationType AUTO 一起工作。在很多关于如何告诉 Hibernate 将 MYSQL 默认为身份而不是表的搜索中,我一无所获。我发现很多人说永远不要使用 table,如果不更改 Hibernate 源代码,就不可能覆盖它。这是一堆废话,让我想知道 Hibernate 开发人员在吸什么。
场景 4: 试图使 H2 与 GenerationType IDENTITY 一起工作。我在这里遇到了一些运气:
-
将
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MODE=MYSQL
放入 test.properties 文件中。
用 @TestPropertySource(locations= "classpath:test.properties")
和 @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
注释我的测试类
这消除了空约束错误,但我现在得到了The database returned no natively generated identity value
。据推测,这是因为,虽然实际的 SQL 代码具有 auto_increment 的 id,但用于为 H2 生成表的任何魔法都无法到达那里。
附录:所有这一切真正令人沮丧的是,它对大多数表都工作得很好。在我的数据库中的 20 多个表中,除了两个表之外,所有表都可以使用 IDENTITY 自动生成和增加它们的 id。其中一些会起作用,而另一些不会起作用,这完全没有意义。
【问题讨论】:
默认生成为身份 不是我见过的 MySQL 或 H2 子句。如果那是正在生成的 SQL,则说明您的配置有问题。 GenerationType.IDENTITY sets 总是在将 id 发送到 db 之前将其设置为 null,这会导致以下错误。 对于 H2,您可以在保存之前手动设置该值,而无需任何问题。对于 SQL Server 等其他数据库,您需要 [暂时] 启用身份插入。 @AlanHay 手动设置值不起作用。仍然为 Id 获取 null。我假设 默认生成为身份 是 Hibernate 消息,而不是 SQL 消息。我知道那不是 SQL。 @AlanHay 好吧,我猜 默认生成为身份 是其他数据库如何以 MySQL 的方式进行的。据我所知,这包括 H2。我不确定你为什么认为那不是 H2。也许只是因为这不是在 H2 中自动递增的正常方式? 因为 H2 和 MySQL 会简单地为列定义指定 auto_increment。你能在 github 上分享你的项目吗?因为我已经做了几十次了,没有任何问题,应该很简单。 【参考方案1】:问题是另一个带有@Table(name = "user")
注释的模型。该模型还定义了 Id 列,但没有生成值。由于冲突,Hibernate 选择了那个来定义 id。
【讨论】:
【参考方案2】:MySql 与
配合使用效果更好@GeneratedValue(strategy = GenerationType.AUTO)
它也更好,因为它在大多数 RDBMS 中生成自动增量主键
【讨论】:
是的,构建它的团队告诉我他们出于某种原因必须明确使用 IDENTITY,而且由于我对 Java 不是很熟悉,所以我没有质疑它,但我想我需要质疑它。 :) 是的,由于缺少表 hibernate_sequence 而出现 AUTO 错误。以上是关于通过使用 MySQL 的 DataJpaTest 存储库测试,Hibernate 不会在 H2 DB 中将用户设置为自动增量的主要内容,如果未能解决你的问题,请参考以下文章