简体   繁体   English

为什么@OneToMany 关系会生成额外的 SQL select 查询?

[英]Why @OneToMany relations generate additional SQL select queries?

@Entity
public class Author  {
    @OneToMany(cascade = {PERSISTE, MERGE},
            mappedBy = "author")
    private List<Book> books = new ArrayList<>();
    
    public void addBook(Book book) {
        this.books.add(book);
        book.setAuthor(this);
    }
    
    //other fields
    
}
    
@Entity
public class Book{


    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "author_id")
    private Author author;
}

public class BookService {

    AuthorRepository repository;

    @Transactional
    public void saveBooks(){

    Book newBook = new Book);
    
    Author author = repository.findByid(1L);
    author.addBook(newBook);
    }
}

In a database, an author already contains one book.在数据库中,一位作者已经包含一本书。 I create a new book for an author and want to save it.我为一位作者创建了一本新书并想保存它。

But when the function addBook is called the existing book is loaded from the database.但是当 function addBook 被调用时,现有的书是从数据库中加载的。 I see the additional SQL query in logs: @Query["select book...."]我在日志中看到额外的 SQL 查询:@Query["select book..."]

How can I fix it?我该如何解决? I don't want to have additional SQL selects我不想有额外的 SQL 选择

This is just how PersistentBag works - Hibernate loads it when you perform action on list.这就是 PersistentBag 的工作原理 - Hibernate 在您对列表执行操作时加载它。 I would simply replace adding new Book to Author's books list with referencing created Book to existing Author我会简单地用将创建的书引用到现有作者来代替将新书添加到作者的书列表

public class BookService {

    BookRepository bookRepository;
    AuthorRepository authorRepository;

    @Transactional
    public void saveBooks() {

        Book newBook = new Book();

        Author author = authorRepository.findByid(1L);
        newBook.setAuthor(author);
        bookRepository.save(newBook);
    }
}

The reason for this is the basic premise under which JPA works: You load an object graph, you manipulate it, at the end of the transaction JPA makes sure the changes end up in the database.这样做的原因是 JPA 工作的基本前提:你加载一个 object 图,你操作它,在事务结束时 JPA 确保更改最终在数据库中。

I see two ways to avoid the select.我看到有两种方法可以避免 select。

  1. reverse the relationship: When the Book references the Author there is no need to load the collection, since it doesn't even exist in the first place.反转关系:当Book引用Author时,无需加载集合,因为它根本不存在。 If you actually need the collection you can always use a dedicated query for that.如果您确实需要该集合,您始终可以为此使用专用查询。

  2. Drop back to SQL and just execute a SQL insert statement.回到 SQL 并执行 SQL 插入语句。 Of course this can lead to inconsistencies between your database and the 1st level cache of JPA. Make sure you understand how the 1st level cache works and what it is used for.当然,这会导致您的数据库与 JPA 的一级缓存不一致。请确保您了解一级缓存的工作原理及其用途。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM