hibernate Sping Boot 测试@Sql & H2给出JdbcSQLIntegrityConstraintViolationException:唯一索引或主键冲突

o8x7eapl  于 2023-04-12  发布在  其他
关注(0)|答案(1)|浏览(243)

我有一个简单的Sping Boot (2.6.1)测试,它抛出:

JdbcSQLIntegrityConstraintViolationException: 
 Unique index or primary key violation

该测试从test/resources/data.sql加载数据,其中包含一个语句:

INSERT INTO country (name) VALUES ('Italy');

测试类是:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    public class FailingTest {

   @Test
   @Sql("/data.sql")
   void test(){
       assertTrue(true);
   }
}

域类为:

@Entity 
public class Country {
   @Id
   @GeneratedValue(strategy = IDENTITY)
   private Integer id;

   @Column(nullable = false, unique = true)
   private String name;
}

application.properties文件包含:

spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.jpa.defer-datasource-initialization=true

异常消息为:

org.springframework.jdbc.datasource.init.ScriptStatementFailedException:
Failed to execute SQL script statement #1 of class path resource [data.sql]: 
INSERT INTO country (name) VALUES ('Italy'); 
nested exception is org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: 
Unique index or primary key violation: 
"PUBLIC.UK_LLIDYP77H6XKEOKPBMOY710D4_INDEX_6 ON PUBLIC.COUNTRY(NAME) 
VALUES ( /* key:1 */ 2, 'Italy')"; 
SQL statement:INSERT INTO country (name) VALUES ('Italy') [23505-200]

应用中没有其他sql脚本,sql数据也没有以编程方式加载,Country没有被其他实体引用。测试作为单个测试运行。
看起来INSERT语句被执行了两次,这违反了列的唯一条件。但是为什么呢?!
当我用@Column(nullable = false)替换@Column(nullable = false, unique = true)时,一切都很好!
你知道发生了什么事吗?有什么办法吗?

sh7euo9m

sh7euo9m1#

这里的问题是关于Sping Boot 自动配置功能。框架将名为data.sql的文件视为默认初始化器。这里实际发生了什么:
1.当应用程序上下文完全配置时,Sping Boot 将执行data.sql作为初始SQL源。
1.当JUnit调用test()方法时,由于存在@Sql注解,它会尝试再次执行data.sql
1.违反唯一约束。引发异常。
有多种方法可以处理这个问题:
1.更改文件的名称(例如,init-data.sql)。在这种情况下,Spring不会在application context start时执行它。
1.将Sping Boot spring.datasource.initialization-mode属性更改为never
1.将脚本移动到任意子文件夹。

相关问题