简体   繁体   中英

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. I see the additional SQL query in logs: @Query["select book...."]

How can I fix it? I don't want to have additional SQL selects

This is just how PersistentBag works - Hibernate loads it when you perform action on list. 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.

I see two ways to avoid the 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. 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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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