java - orphanRemoval 在 PostgreSQL 中工作但在 hsqldb 中不起作用

标签 java hibernate postgresql unit-testing hsqldb

我有学院实体:

@Entity
@Table(name = "academy")
public class Academy {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(nullable = false)
private String name;

@Column(nullable = false)
private String address;

@OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "parent")
private List<Institute> institutes;

public Academy() {}

public Academy(String name, String address, List<Institute> institutes) {
    this.name = name;
    this.address = address;
    this.institutes = institutes;
}

研究所实体:

@Entity
@Table(name = "institute")
public class Institute {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column
private String name;

@Column(name = "building_code")
private String buildingCode;

@ManyToOne(optional = false)
private Academy parent;

@OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "parent")
private List<Department> departments;


public Institute() {}

public Institute(String name, String buildingCode, Academy parent, List<Department> departments) {
    this.name = name;
    this.buildingCode = buildingCode;
    this.parent = parent;
    this.departments = departments;

    parent.getInstitutes().add(this);
}

这个想法是,Academy 是父级,Institute 是子级(树状结构)。 学院部门 - 但目前并不重要。当删除 Academy 时(类 UnitServiceImpl. java):

@Override
@Transactional
public String remove(String whatIsRemoved, Long id) {
    if (whatIsRemoved.equals("academy")){
        Academy academy = getAcademyById(id);
        academy.getInstitutes().clear();
        getCurrentSession().delete(academy);
    }
    else if (whatIsRemoved.equals("institute")){
        Institute institute = getInstituteById(id);
        institute.getParent().getInstitutes().remove(institute);
    }
    //other if's etc..
}

当我使用应用程序时,一切似乎都正常 - 当我删除Academy时,与该Academy及其相关的每个Institute 部门等已从数据库中删除(我使用的是PostgreSQL 9.3)。简而言之 - 它表现为树状结构。但是,如果我尝试使用内存数据库编写单元测试(我在 2.3.2 版本中使用 hsqldb),这应该证明这一点:

@Test
@Transactional
public void test_WhenAcademyWasRemoved_InstitutesAlsoShouldBeRemoved() throws Exception {
    UnitServiceImpl service = new UnitServiceImpl();
    service.setSessionFactory(sessionFactory);

    AcademyDTO michigan = new AcademyDTO(null, "Michigan", "test");
    service.saveAcademy(michigan);
    service.saveInstitute(new InstituteDTO(null, "IT", "D", getAcademyIdByName(service, "Michigan"), null));
    service.remove("academy", getAcademyIdByName(service, "Michigan"));

    List<Institute> institutes = (List<Institute>)sessionFactory.getCurrentSession().createCriteria(Institute.class).list();
    assertEquals(0, institutes.size());
}

与“密歇根”相关的机构仍在数据库中,以“密歇根”为父级,并且测试崩溃。这意味着我错了,在 PostgreSQL 数据库中它们也没有被删除(但我检查它并且 Instututes 为空)?或者,这仅意味着当提交 Transaction 时它们将被删除?因为测试方法需要是@Transactional,没有它测试将无法编译 - 但是,如何测试它呢?我被困住了,因为在应用程序中它看起来不错,但在内存数据库的单元测试中它不能像我认为的那样工作。如果有人帮助我,我将非常高兴 - 预先感谢您。 更新:问题是:orphanRemoval = true在本地主机数据库上工作,在我看来,因为事务已提交,然后应用级联删除。我如何在单元测试中以不太复杂的方式做同样的事情 - 比如在测试结束之前提交事务(触发级联删除),然后使用另一个 Transaction 获取 Institute ?我在测试中尝试了私有(private) @Transactional 方法,但它不起作用。

最佳答案

我认为问题可能在于测试中的事务处理方式与“正常”代码中的处理方式不同(这让我一次又一次感到困惑)。

让我们验证一下我是否正确理解您的问题:

当您使用 mysql 数据库运行应用程序时,一切正常。

但是当您针对 hsqldb 级联删除运行测试时似乎失败了。

我认为这两种场景之间的区别在于事务的处理,更重要的是更改从 session 刷新到数据库的时间,即 sql 语句实际执行的时间。

要验证这一点,您可以激活 SQL 日志记录以查看数据何时存储在数据库中。我的期望是,在生产中,这种情况最晚会在每个 @Transactional 方法结束时发生,但在测试中,由于测试上的 @Transactional 注释,所有内容都在单个事务中运行,并且不会发生刷新,或者至少不会同时发生时间点。

为了模拟生产行为,您可以在事务通常结束的地方添加对 Session.flush 的调用。

关于java - orphanRemoval 在 PostgreSQL 中工作但在 hsqldb 中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30156908/

相关文章:

postgresql - Lambda + RDS Postgres 不工作

ruby-on-rails - Activerecord 将 UUID 读取为整数。我需要实际的 UUID 作为字符串

java - 如果转换为其实现的接口(interface),则获取原始类

javascript - Web 应用程序中的文件夹选择器 - PrimeFaces 还是 JavaScript?

java - 无法取消 Android 闹钟管理器的闹钟

Java Regex 捕获多个匹配项

java - 即使凭据正确,Spring-security 也不会登录用户

java - 如何在Spring Boot中显示mysql View ?

java - 从数据库中选择 MappedSuperclass (Hibernate)

mysql - 可扩展的启动持久性