测试 Hibernate @Check 约束时无法生成约束冲突异常

pir*_*rho 1 java hibernate jpa h2 spring-boot

我正在使用 Hibernate@Check注释,但在不满足约束时不能让我的测试失败。目前只使用带有 H2 数据库的默认 Spring 启动配置。

我错过了什么?如果真有某种的冲洗save(..)

运行测试时,我看到正确创建的表。如果我从日志中复制创建行并使用它创建一个表到我的“真实”Postgres 数据库,我可以测试不同的插入并看到这条线在约束条件下一切正常。

实体

@Getter @Setter
@Entity @Check(constraints = "a IS NOT NULL OR b IS NOT NULL")
public class Constrained {

    @Id @GeneratedValue
    private Long id;

    private String a, b;
}
Run Code Online (Sandbox Code Playgroud)

测试

@DataJpaTest
@RunWith(SpringRunner.class)
public class HibernateCheckTest {

    @Resource // this repo is just some boiler plate code but attached at 
              // the bottom of question
    private ConstrainedRepository repo;

    @Test @Transactional // also tried without @Transactional
    public void test() {
        Constrained c = new Constrained();
        repo.save(c); // Am I wrong to expect some constraint exception here?
    }
}
Run Code Online (Sandbox Code Playgroud)

运行测试时的表生成脚本

创建表约束(id bigint not null,a varchar(255),b varchar(255),主键(id),检查(a IS NOT NULL OR b IS NOT NULL))

存储库(在 repo 中看不到太多,只是为了显示它):

public interface ConstrainedRepository
            extends CrudRepository<Constrained, Long> {
}
Run Code Online (Sandbox Code Playgroud)

然而

如果我使用EntityManagerso 添加到我的测试类:

@PersistenceContext
private EntityManager em;
Run Code Online (Sandbox Code Playgroud)

并像这样坚持下去:

em.persist(c);
em.flush();
Run Code Online (Sandbox Code Playgroud)

而不是repo.save(c)我会得到例外。

repo.save(c)更仔细地研究原始测试中的日志:

org.springframework.test.context.transaction.TransactionContext:139 - 回滚测试事务:
...
testException = [null],

所以出于某种原因,这个错误只是被包装和记录。使用存储库进行持久化时如何“解开”并抛出它?

pir*_*rho 6

感谢codemonkey回答,我找到了解决方案。这可以通过添加以下内容来解决:

@org.springframework.transaction.annotation.Transactional(propagation = 
                                                     Propagation.NOT_SUPPORTED)
Run Code Online (Sandbox Code Playgroud)

到我的测试班。


cod*_*key 5

ConstrainedRepository,扩展JpaRepository而不是CrudRepository然后使用:

repo.saveAndFlush(c);
Run Code Online (Sandbox Code Playgroud)

代替:

repo.save(c);
Run Code Online (Sandbox Code Playgroud)

检查在数据库中强制执行,并且仅在更改(在本例中为 INSERT 语句)刷新到数据库时才会发生。

如果没有显式刷新,Hibernate 将推迟将语句发送到数据库,直到提交事务或执行查询。

但是,来自 Spring DataJpaTest文档:

默认情况下,数据 JPA 测试是事务性的,并在每次测试结束时回滚。

所以,在这种情况下,没有提交。事务回滚并且语句永远不会刷新到数据库,因此永远不会抛出异常。