我有一个简单的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)
时,一切都很好!
你知道发生了什么事吗?有什么办法吗?
1条答案
按热度按时间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.将脚本移动到任意子文件夹。