find() vs getReference() in Hibernate 7: A Decision Matrix (and Why get()/load() Belong in the Same Conversation)
Read this code and predict whether it sends a SELECT to the database: @Transactional public void assignCategory(Long productId, Long categoryId) { Category category = em.getReference(Category.class, categoryId); Product product = em.find(Product.class, productId); product.setCategory(category); } If you said "two SELECTs" — one for each line — you would be half wrong. find() on Product does hit the database. getReference() on Category does not, unless categoryId is already in the first-level cache. The UPDATE to write category_id to the product row happens at flush; the category column only needs the ID, which the proxy already holds. That single avoided SELECT matters in bulk operations. It is also one of the most consistently misunderstood distinctions in Hibernate. This post is a decision guide: six scenarios, each with the right call and the reasoning.