Java 存储库保存的工作方式与spring boot中的controller或commandlinerunner不同

Java 存储库保存的工作方式与spring boot中的controller或commandlinerunner不同,java,spring,controller,entity,spring-transactions,Java,Spring,Controller,Entity,Spring Transactions,我有两种情况,当从不同的上下文调用子实体save时,它们的工作方式不同。 当我在没有级联父级的情况下更新子级时,修改后的数据也会更新,但如果我从CommandLineRunner调用父级更新,则这只会从控制器中发生 这是我的服务 @服务 公共类图书服务{ 私人最终书库作者或保存书库作者或保存书库; 私人最终图书库; @自动连线 公共图书服务(BookAuthorRepository BookAuthorRepository,BookRepository BookRepository){ this

我有两种情况,当从不同的上下文调用子实体save时,它们的工作方式不同。 当我在没有级联父级的情况下更新子级时,修改后的数据也会更新,但如果我从
CommandLineRunner
调用父级更新,则这只会从控制器中发生

这是我的服务

@服务
公共类图书服务{
私人最终书库作者或保存书库作者或保存书库;
私人最终图书库;
@自动连线
公共图书服务(BookAuthorRepository BookAuthorRepository,BookRepository BookRepository){
this.bookAuthorRepository=bookAuthorRepository;
this.bookRepository=bookRepository;
}
public void updateBookAuth(){
Book Book=bookRepository.findById(3.get();
book.setName(“不应更新”);
book.getBookAuthor().setName(“新名称”);
bookAuthorRepository.save(book.getBookAuthor());
}
}
当我从下面的类中调用它时,只更新
BookAuthor
name,这是正确的行为

@组件
公共类MyRunner实现CommandLineRunner{
@自动连线
私人图书服务;
@凌驾
公共无效运行(字符串…参数)引发异常{
bookService.updateBookAuth();
}
}
但如果我从控制器调用此服务方法:

@RestController
公共类图书管理员{
私人最终图书服务;
公共图书管理员(图书服务图书服务){
this.bookService=bookService;
}
@GetMapping(“/”)
公开无效测试(){
bookService.updateBookAuth();
}
}
然后
Book
name和
BookAuthor
name都被更新了,但我不明白为什么
Book
name会被更新

以下是实体:

@实体
公共课堂用书{
@身份证
@GeneratedValue(策略=GenerationType.IDENTITY)
私有整数id;
私有字符串名称;
@奥内托内
私人书籍作者;
公共字符串getName(){
返回名称;
}
公共void集合名(字符串名){
this.name=名称;
}
公共无效集合id(整数id){
this.id=id;
}
公共整数getId(){
返回id;
}
PublicBookAuthor getBookAuthor(){
返回图书作者;
}
公共无效书库作者(图书作者){
this.bookAuthor=bookAuthor;
}
}
@实体
公共类图书作者{
@身份证
@GeneratedValue(策略=GenerationType.IDENTITY)
私有整数id;
私有字符串名称;
@OneTONE(mappedBy=“bookAuthor”)
私人书籍;
公共字符串getName(){
返回名称;
}
公共void集合名(字符串名){
this.name=名称;
}
公共无效集合id(整数id){
this.id=id;
}
公共整数getId(){
返回id;
}
公共图书{
还书;
}
公共作废退册(书){
这本书;
}
}

我还考虑了事务性,如果我在方法上写事务,那么所有上下文都会打开,父-子上下文都会更新,但在这种情况下,我不使用它,所以为什么会发生这种情况?

要真正理解正在发生的事情,您需要了解Hibernate是如何工作的,尤其是Hibernate会话。这是一篇好文章。在BookService类中,您专门为bookauthor设置了新名称,因为此事务是会话的一部分,所以它也将更新它。Spring Data JPA非常有用,但您必须熟悉Hibernate才能完全理解其行为。

您可以检查从存储库中获取的图书实体是否仍处于管理状态。为此,我们可以直接在服务中插入实体管理器,并添加如下日志语句:

    @Service
    @RequiredArgsConstructor
    public class BookService {
    
      private final BookBookAuthorRepository bookAuthorRepository;
      private final BookRepository bookRepository;
      private final EntityManager entityManager;
    
      public void updateBookAuth() {
        Book book = bookRepository.findById(1L).get();
    
        System.out.println("----------> is managed: " + entityManager.contains(book));
    
        book.setName("should not update");
        book.getBookAuthor().setName("new name");
        bookAuthorRepository.save(book.getBookAuthor());
      }
    
    }
现在,当您从MyRunner调用updateBookAuth函数时,它将打印:

---------->被管理:false

当您从BookController调用updateBookAuth函数时,它将打印:

---------->这是真的

这意味着在rest控制器的情况下,数据库操作是在单个持久性会话中执行的,因此book和author实体都被更新

在命令行运行程序的情况下,图书实体查询在单独的持久性会话中执行,然后分离,而作者实体更新在单独的持久性会话中执行,因为图书实体更新丢失

这是因为SpringWeb框架默认情况下将持久性会话和请求生命周期联系在一起。这样实现是为了防止视图层中的延迟初始化关联出现问题

要防止此行为,可以在应用程序.properties文件中使用以下设置禁用它:

spring.jpa.openin-view=false


请在此

中阅读有关此功能的更多信息问题是我确切地知道如何使用ejb transactionmanagement.bean处理此案例,所以我看到的问题是缺乏关于spring controller如何处理数据库会话的知识,无论如何,谢谢您的评论谢谢您的回答