在 HSQLDB 上使用 Spring DBUnit 进行休眠和 Spring 数据 - 由于外键约束而无法删除

Posted

技术标签:

【中文标题】在 HSQLDB 上使用 Spring DBUnit 进行休眠和 Spring 数据 - 由于外键约束而无法删除【英文标题】:Hibernate and Spring Data with Spring DBUnit on HSQLDB - Unable to delete due to foreign key constraint 【发布时间】:2015-07-17 20:44:47 【问题描述】:

我正在使用 Hibernate 和 Spring Data 对一个非常简单的域进行建模:

@Entity
public class User implements Serializable 

    private static final long serialVersionUID = -5501812656863255674L;

    @Id
    private String emailAddress;

    @Column
    private String forename;

    @Column
    private String surname;

    @Column
    @Enumerated(EnumType.STRING)
    private UserRole role;

    @OneToMany(cascade =  CascadeType.ALL )
    private List<Team> teams;

@Entity
public class Team implements Serializable 

    private static final long serialVersionUID = -3734641391628154428L;

    private static final BigDecimal STARTING_BUDGET = new BigDecimal(100);

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    @Column(unique = true)
    private String name;

然后,我在数据服务中有一个“updateUser”方法,该方法按其命名。这个想法是为了给一个用户添加一个团队,这个方法会被使用,并且级联会导致团队被持久化在数据库中。

@Override
    public void updateUser(final User user) throws IntegrationException 

        if (userRepository.exists(user.getEmailAddress())) 
            userRepository.save(user);
         else 
            throw new IntegrationException(IntegrationExceptionCode.USER_NOT_FOUND);
        
    

然后我使用 HSQLDB 数据库和 Spring DBUnit 对该方法进行单元测试,以设置初始数据库内容和预期的数据库内容:

初始数据库内容配置

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
    <User emailAddress="user1@test.com" forename="User" surname="One" role="MANAGER" />
    <Player />
    <User_Team />
    <Team />
</dataset>

预期的数据库内容配置

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
    <User emailAddress="user1@test.com" forename="User" surname="One" role="MANAGER" />
    <Player />
    <Team id="1" name="Test Team" totalScore="0" status="INCOMPLETE" remainingBudget="100" />
    <User_Team User_emailAddress="user1@test.com" Teams_id="1" />
</dataset>

然后我有两个测试:一个测试更新是否成功;一种测试尚未在系统中的用户无法更新的方法。

成功测试

@Test
@ExpectedDatabase("UserData-WithTeam.xml")
public void testUpdateUser_AddedTeam_Success() throws Exception 
    // arrange
    final User user = UserTestDataBuilder.aManager(VALID_EMAIL_ADDRESS, "User", "One").withTeam().build();

    // act
    userDataService.updateUser(user);

    // assert - done by @ExpectedDatabase annotation

“用户不存在”测试

@Test
    public void testUpdateUser_AddedTeam_UserDoesNotExist() throws Exception 
        // arrange
        thrownException.expect(IntegrationException.class);
        thrownException.expect(CustomIntegrationExceptionMatcher.hasCode(IntegrationExceptionCode.USER_NOT_FOUND));

        final User user = UserTestDataBuilder.aManagerWithEmailAddress(INVALID_EMAIL_ADDRESS).withTeam().build();

        // act
        userDataService.updateUser(user);

        // assert
        Assert.fail("Exception expected");
    

“成功”测试运行良好。但是,“失败案例”测试错误并出现以下错误:

java.sql.SQLIntegrityConstraintViolationException: integrity constraint violation: foreign key no action; FK_RVG5KHM9RO439HI17HPAUV5KG table: USER_TEAM
    at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
    at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
    at org.hsqldb.jdbc.JDBCStatement.fetchResult(Unknown Source)
    at org.hsqldb.jdbc.JDBCStatement.execute(Unknown Source)
    at org.dbunit.database.statement.SimpleStatement.executeBatch(SimpleStatement.java:69)
    at org.dbunit.operation.DeleteAllOperation.execute(DeleteAllOperation.java:126)
    at org.dbunit.operation.CompositeOperation.execute(CompositeOperation.java:79)
    at com.github.springtestdbunit.DbUnitRunner.setupOrTeardown(DbUnitRunner.java:194)
    at com.github.springtestdbunit.DbUnitRunner.beforeTestMethod(DbUnitRunner.java:66)
    at com.github.springtestdbunit.DbUnitTestExecutionListener.beforeTestMethod(DbUnitTestExecutionListener.java:186)
    at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:249)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:72)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
    at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:239)
    at org.junit.rules.RunRules.evaluate(RunRules.java:20)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:224)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.hsqldb.HsqlException: integrity constraint violation: foreign key no action; FK_RVG5KHM9RO439HI17HPAUV5KG table: USER_TEAM
    at org.hsqldb.error.Error.error(Unknown Source)
    at org.hsqldb.StatementDML.performReferentialActions(Unknown Source)
    at org.hsqldb.StatementDML.delete(Unknown Source)
    at org.hsqldb.StatementDML.executeDeleteStatement(Unknown Source)
    at org.hsqldb.StatementDML.getResult(Unknown Source)
    at org.hsqldb.StatementDMQL.execute(Unknown Source)
    at org.hsqldb.Session.executeCompiledStatement(Unknown Source)
    at org.hsqldb.Session.executeDirectStatement(Unknown Source)
    at org.hsqldb.Session.execute(Unknown Source)
    ... 32 more

这似乎是在暗示它不能拆除'success'测试中添加的测试数据(并且我已经在成功测试中添加了@Ignore注释并且失败测试通过了)。我的问题是为什么?我在 @OneToMany 关系上的级联设置为 ALL,因此应删除作为用户-团队关系一部分保存的所有实体。

有人有什么想法吗?

【问题讨论】:

【参考方案1】:

我认为您在USER_TEAM 表中有一个完整性约束:UPDATE NO ACTION 这就是为什么给java.sql.SQLIntegrityConstraintViolationException: integrity constraint violation: foreign key no action;

【讨论】:

以上是关于在 HSQLDB 上使用 Spring DBUnit 进行休眠和 Spring 数据 - 由于外键约束而无法删除的主要内容,如果未能解决你的问题,请参考以下文章

如何在当前使用 HSQLDB 的 Spring 和 Hibernate 后台使用 MySQL

如何使用注解在 Spring JPA 中定义 HSQLDB 属性

使用 JavaConfig 使用 Spring 应用程序的 HSQLDB 新手

使用 HSQLDB 作为 Spring、Hibernate 的可移植数据库

使用 Spring 进行 HSQLDB 配置 - BeanCreationException:

Spring Batch , HSQLDB 随时间增长