Spring数据更新实体没有事务

swc*_*wch 7 hibernate jpa spring-data

我有 Spring Data 的简单代码示例:

实体

@Entity
@Table(name = "car")
public class Car {

    @Id
    @GeneratedValue
    private Long id;

    private String name;
//...
}
Run Code Online (Sandbox Code Playgroud)

存储库:

@Repository
public interface CarRepository extends JpaRepository<Car, Long> {
}
Run Code Online (Sandbox Code Playgroud)

服务与示例方法:

@Service
public class CarService {

    @Autowired
    private CarRepository carRepository;

    public void change() {
        Car one = carRepository.findOne(1L);
        one.setName("changed"); //important
    }
}
Run Code Online (Sandbox Code Playgroud)

和控制器:

@RestController("/")
public class CarController {

    @Autowired
    private CarRepository carRepository;

    @Autowired
    private CarService carService;

    @GetMapping
    public List<Car> home() {
        carService.change();
        List<Car> all = carRepository.findAll();

        return all;
    }

}
Run Code Online (Sandbox Code Playgroud)

我也有 3 条记录的 data.sql:

insert into car values (1, 'aaa');
insert into car values (2, 'bbb');
insert into car values (3, 'ccc');
Run Code Online (Sandbox Code Playgroud)

当我向 localhost:8080 发送请求时,我得到了三辆汽车的列表,其中第一辆已更新:

insert into car values (1, 'changed');
insert into car values (2, 'bbb');
insert into car values (3, 'ccc');
Run Code Online (Sandbox Code Playgroud)

我的期望是在从控制器调用 change() 之后实际上什么也没有发生,因为这个方法不是事务性的。那么为什么控制器中的 home() 方法返回带有更新实体的列表?

这个问题与这个Spring 数据完全不同jpa @transactional我不明白你为什么把它标记为重复。

小智 6

我假设您正在使用 Spring Boot。如果您将 Spring Boot 与 Spring MVC 和 Spring Data 一起使用,默认情况下,每次控制器方法收到请求时都会打开一个 Hibernate Session。会话提供应用程序和数据库之间的物理连接。此功能可以通过应用程序属性进行控制spring.jpa.open-in-view

Car one = carRepository.findOne(1L); //1
one.setName("changed"); //2
List<Car> all = carRepository.findAll(); //3
return all;
Run Code Online (Sandbox Code Playgroud)
  1. 当程序到达上面的代码时,将打开一个会话。在第一行,从数据库中检索 Car 对象,并将该对象存储在First Level Cache.
  2. 由于“ one ”引用指向缓存中的同一个对象,因此在第 2 行缓存的对象名称发生了变化。
  3. 在第三行,我们获取了之前检索到的对象的缓存值,该值在最后返回。

由于修改后的值永远不会刷新到数据库,因此在控制器调用之后,您可以检查数据库,您将看到,尽管您在控制器响应中收到了不同的值,但旧值仍然保留在您的对象中。

如果您将该spring.jpa.open-in-view属性设置为false,您的控制器将返回“正确”值。