hibernate 刷新JpaRepository后失败的对象,我如何回滚删除?

v64noz0r  于 2023-10-23  发布在  其他
关注(0)|答案(1)|浏览(105)

我试图调整应用程序域模型的删除行为。假设我有国家和地区,如果国家有任何地区,则不应删除。下面将介绍其他类/配置,但下面的代码应该测试它。countryRepository.flush();抛出了一个DataIntegrityViolationException,正如预期的那样,但是对countryRepository.count()的最后一次调用抛出了相同的Exception。在日志中,您可以看到它试图再次执行DELETE SQL命令。
我希望在@Transactional上回滚这种情况,但显然它没有-也许是因为它被assertThrows捕获了?

@SpringBootTest
@SpringBootApplication
@TestPropertySource(locations = "classpath:unit-tests.properties")
@Transactional
public class Tests {
    @Autowired
    private CountryRepository countryRepository;

    @Autowired
    private RegionRepository regionRepository;

    @Test
    public void preventDeleteOfUsedObjects() {
        // Create objects
        Country country = new Country();
        country.name = "United Status";
        countryRepository.save(country);
        countryRepository.flush();
        Region region = new Region();
        region.name = "California";
        region.country = country;
        regionRepository.save(region);
        regionRepository.flush();

        // Deleting used countries should not be possible
        Assertions.assertThrows(DataIntegrityViolationException.class, () -> {
            countryRepository.delete(country);
            countryRepository.flush();
        });

        Assert.assertEquals(1, countryRepository.count());
    }
}

数据模型:

@Entity
@Table(name = "countries")
public class Country {
    @Id
    public String name;
}
@Entity
@Table(name = "regions")
public class Region {
    @Id
    public String name;

    @ManyToOne
    public Country country;
}

对应的存储库:

public interface CountryRepository extends JpaRepository<Country, String> {
}
public interface RegionRepository extends JpaRepository<Region, String> {
}

unit-tests.properties:

spring.datasource.url=jdbc:hsqldb:mem:model;sql.syntax_pgs=true
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.hsqldb.jdbcDriver
spring.jackson.default-property-inclusion=non_null
spring.jpa.hibernate.ddl-auto=create
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
logging.level.root=INFO

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.6</version>
        <relativePath/>
    </parent>
    <artifactId>example</artifactId>
    <name>example</name>
    <properties>
        <maven.compiler.release>11</maven.compiler.release>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
nx7onnlm

nx7onnlm1#

经过更多的实验,我发现Spring将automatically rollback all changes after completing a test method,这是我完全没有预料到的,因为我在应用程序日志中看到了SQL INSERTDELETE语句。我应该知道它们是在BEGIN TRANSACTION之后执行的,但是不能很容易地检查结果,因为我在没有管理工具的情况下使用HSQLDB进行单元测试。我在项目中还有其他的“单元测试”(没有标记为@Transactional,在属性文件中有一个不同的数据库连接),用于在PostgreSQL数据库中生成一些引导数据,这些数据库按预期工作,并持久化数据。
所以现在我先结束测试

Assert.assertEquals(1, countryRepository.count());

希望我不会愚蠢到在我的主代码中捕获DataIntegrityViolationException s。

相关问题