<Spring Boot / Hibernate> 插入前删除未完成

Posted

技术标签:

【中文标题】<Spring Boot / Hibernate> 插入前删除未完成【英文标题】:<Spring Boot / Hibernate> Delete not completed before Insert 【发布时间】:2020-11-24 04:06:35 【问题描述】:

您好,我正在使用 Spring Boot hibernate 在 mysql 中测试记录 delete-insert-delete 操作,我注意到一个问题,即插入发生时似乎没有完全删除记录。

在 hibernate kickstart 上创建 3 个初始记录(通过类路径中的 data.sql)

insert into car(id, name, color) values (1, 'Toyota Camry', 'blue');
insert into car(id, name, color) values (2, 'Suzuki Swift', 'yellow');
insert into car(id, name, color) values (3, 'Nissan Qashqai', 'red');

操作是 (1) 创建的初始记录 (2) 删除所有记录 (3) 添加新记录 (4) 删除所有记录

进行断言时,发现结果列表仍然包含最后一条记录,因此断言失败。

我想知道这是否是由于在插入之前没有完成删除操作造成的。

感谢您对此提供一些见解,非常感谢。

模型(Car.java):

package com.example.demo.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

@ApiModel(value = "Car", description = "The model for car")
@Schema
@Entity
@Data
public class Car 
    @ApiModelProperty(notes = "Car ID.", example = "12345", required = false, position = 0)
    @Id
    @GeneratedValue
    private Long id;

    @ApiModelProperty(notes = "Car name.", example = "Suzuki Swift 2020", required = true, position = 1)
    @NotNull
    @Size(min = 1, max = 30, message = "Name must have length between 1 and 30")
    private String name;

    @ApiModelProperty(notes = "Car color.", example = "blue", required = true, position = 2)
    @NotNull
    @Size(min = 1, max = 30, message = "Color must have length between 1 and 30")
    private String color;

存储库 (CarReposiroty.java)

package com.example.demo.repo;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.example.demo.model.Car;

@Repository
public interface CarRepository extends JpaRepository<Car, Long> 


服务(TestService.java)

package com.example.demo.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.example.demo.model.Car;
import com.example.demo.repo.CarRepository;

@Service
public class TestService 

    @Autowired
    private CarRepository carRepository;

    public List<Car> getAllCars() 
        return carRepository.findAll();
    

    @Transactional
    public void addNewCar(Car car) 
        carRepository.save(car);
    

    @Transactional
    public void deleteAllCars() 
        carRepository.deleteAll();
    

JUnit

...
......
@Test
public void shouldBeAbleToDeleteCarAndAddCarAndGetAllCars() 
    testService.deleteAllCars();

    Car car = new Car();
    car.setName("123456789012345678901234567890");
    car.setColor("123456789012345678901234567890");

    testService.addNewCar(car);

    List<Car> carList = testService.getAllCars();

    assertEquals(1, carList.size());

    testService.deleteAllCars();

...
......

Spring Boot v2.3.1

pom.xml

    ...
    .....
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    ...
    ......

Spring 休眠配置 (application-test.yml)

spring.datasource.url: jdbc:mysql://[the host url]:3306/test
spring.datasource.username: [the username]
spring.datasource.password: [the password]
spring.jpa.hibernate.ddl-auto: create-drop
spring.datasource.initialization-mode: always

MySQL 8.0.17

【问题讨论】:

删除后应该没有记录了。然后执行更新以添加 1 条新记录。断言断言应该只有 1 条记录。但是,实际结果是有 2 条记录(1)最后一条(前两条已按预期删除)(2)我们新添加的一条 【参考方案1】:

这是因为deleteAllCars() 没有将更改提交到数据库,并且测试方法中的所有操作都包装在单个事务中,因为正在传播事务。在测试类上添加以下注释

@Transactional(propagation = Propagation.NEVER)

也检查这个相关问题How to flush data into db inside active spring transaction?

【讨论】:

嗨@Arghya Sadhu,谢谢。事实上,我尝试在 JUnit 测试方法中添加 Transaction 注释,它可以按预期完成。所以我想知道问题实际上是测试方法中的操作没有被包装在同一个事务中,即允许在删除完成之前继续读取? 这应该会给你一些线索javacodegeeks.com/2011/12/…

以上是关于<Spring Boot / Hibernate> 插入前删除未完成的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate入门-----Hiberna核心文件详解

springboot functions

spring boot系列spring boot 使用mongodb

Spring boot 入门三:spring boot 整合mybatis 实现CRUD操作

我的spring和hibernate配置的一直报错,空指针

Spring BootSpring Boot之两种引入spring boot maven依赖的方式