我有两个例子,当从不同的上下文调用时,子实体save的工作方式不同。当我在没有级联父级的情况下更新子级时,修改后的数据也会被更新,但这只发生在从控制器调用时 CommandLineRunner
父级更新不会发生。
这是我的服务
@Service
public class BookService {
private final BookAuthorRepository bookAuthorRepository;
private final BookRepository bookRepository;
@Autowired
public BookService(BookAuthorRepository bookAuthorRepository, BookRepository bookRepository) {
this.bookAuthorRepository = bookAuthorRepository;
this.bookRepository = bookRepository;
}
public void updateBookAuth() {
Book book = bookRepository.findById(3).get();
book.setName("should not update");
book.getBookAuthor().setName("new name");
bookAuthorRepository.save(book.getBookAuthor());
}
}
当我从下面的类调用它时,只有 BookAuthor
名称被更新,这是正确的行为。
@Component
public class MyRunner implements CommandLineRunner {
@Autowired
private BookService bookService;
@Override
public void run(String... args) throws Exception {
bookService.updateBookAuth();
}
}
但如果我从控制器调用此服务方法:
@RestController
public class BookController {
private final BookService bookService;
public BookController(BookService bookService) {
this.bookService = bookService;
}
@GetMapping("/")
public void test() {
bookService.updateBookAuth();
}
}
然后两者 Book
姓名和 BookAuthor
名字更新了,但我不明白为什么 Book
名称已更新。
以下是实体:
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
@OneToOne
private BookAuthor bookAuthor;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
public BookAuthor getBookAuthor() {
return bookAuthor;
}
public void setBookAuthor(BookAuthor bookAuthor) {
this.bookAuthor = bookAuthor;
}
}
@Entity
public class BookAuthor {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
@OneToOne(mappedBy = "bookAuthor")
private Book book;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
}
我还考虑了事务性,如果我在方法上写事务,那么所有上下文都会打开,父-子上下文都会更新,但在这种情况下,我不使用它,为什么会发生这种情况?
4条答案
按热度按时间34gzjxbg1#
2wnc66cl2#
当您从存储库中获取图书实体时,可以检查它是否仍处于管理状态。为此,我们可以在服务中直接插入实体管理器,并添加如下日志语句:
现在,当您从myrunner调用updatebookauth函数时,它将打印:
hgb9j2n63#
要真正理解发生了什么,您需要了解hibernate是如何工作的,尤其是hibernate会话。这是一篇好文章https://www.baeldung.com/hibernate-save-persist-update-merge-saveorupdate . 在bookservice类中,您专门为bookauthor设置了一个新名称,因为这个事务是会话的一部分,所以它也会更新它。springdatajpa非常有用,但是您必须熟悉hibernate才能完全理解其行为。
aiqt4smr4#