有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

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

我错过了什么?在save(..)之后是否应该有某种刷新

运行测试时,我看到正确创建的表。如果我从日志中复制创建行并使用它创建一个表到我的“real”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;
}

测试

@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?
    }
}

运行测试时的表生成脚本

create table constrained (id bigint not null, a varchar(255), b varchar(255), primary key (id), check (a IS NOT NULL OR b IS NOT NULL))

存储库(在回购协议中看不到多少,只是为了展示它):

public interface ConstrainedRepository
            extends CrudRepository<Constrained, Long> {
}

但是

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

@PersistenceContext
private EntityManager em;

然后像这样做:

em.persist(c);
em.flush();

我将得到异常,而不是repo.save(c)

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

org.springframework.test.context.transaction.TransactionContext:139 - Rolled back transaction for test:
...
testException = [null],

因此,出于某种原因,这个错误只是包装和记录。在使用存储库进行持久化时,如何将其“展开”并抛出


共 (2) 个答案

  1. # 1 楼答案

    多亏了codemonkeyanswer,我找到了一个解决方案。通过添加以下内容解决此问题:

    @org.springframework.transaction.annotation.Transactional(propagation = 
                                                         Propagation.NOT_SUPPORTED)
    

    去我的测试班

  2. # 2 楼答案

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

    repo.saveAndFlush(c);
    

    而不是:

    repo.save(c);
    

    检查是在数据库中强制执行的,只有当更改(在本例中是INSERT语句)刷新到数据库时才会发生

    在没有显式刷新的情况下,Hibernate will defer将语句发送到数据库,直到提交事务或执行查询为止

    然而,从Spring DataJpaTest文档中:

    By default, data JPA tests are transactional and roll back at the end of each test.

    因此,在这种情况下,没有提交。事务被回滚,语句永远不会刷新到数据库,因此永远不会引发异常