Ba method liên quan đến Persistence Context (first-level cache của Hibernate).
save(entity):
- Đưa entity vào Persistence Context.
- Chưa chắc execute SQL ngay — đợi đến khi flush (commit transaction, query cần dữ liệu mới).
flush():
- Ép Persistence Context đồng bộ xuống DB — execute SQL pending.
- Không commit transaction — nếu có lỗi sau flush, vẫn rollback được.
saveAndFlush(entity):
- Tương đương save() + flush() ngay lập tức.
- Dữ liệu xuống DB ngay, nhưng transaction chưa commit.
// save() — không cần ngay
User user = userRepo.save(new User("alice"));
// SQL: chưa chắc execute ngay
// saveAndFlush() — cần ID ngay sau save (DB-generated)
User saved = userRepo.saveAndFlush(new User("bob"));
Long id = saved.getId(); // ID đã có vì SQL đã chạy
// flush() — trong cùng 1 transaction, force sync trước native query
userRepo.save(user);
userRepo.flush(); // đảm bảo data xuống trước câu native query bên dưới
int count = entityManager.createNativeQuery(
"SELECT count(*) FROM users WHERE active = true").getSingleResult();Khi dùng saveAndFlush: cần dùng ID/column tự sinh từ DB ngay trong cùng transaction; native query cần thấy data vừa save.
All three relate to the Persistence Context (Hibernate's first-level cache).
save(entity):
- Places the entity into the Persistence Context.
- Does not necessarily execute SQL immediately — waits for a flush (transaction commit, or a query that needs fresh data).
flush():
- Forces the Persistence Context to sync to the DB — executes pending SQL.
- Does NOT commit the transaction — if an error occurs after flush, it can still be rolled back.
saveAndFlush(entity):
- Equivalent to save() + immediate flush().
- Data goes to DB immediately, but the transaction is not committed yet.
// save() — don't need it immediately
User user = userRepo.save(new User("alice"));
// SQL: may not execute immediately
// saveAndFlush() — need the DB-generated ID right away
User saved = userRepo.saveAndFlush(new User("bob"));
Long id = saved.getId(); // ID available because SQL has already run
// flush() — force sync before a native query in the same transaction
userRepo.save(user);
userRepo.flush();
int count = entityManager.createNativeQuery(
"SELECT count(*) FROM users WHERE active = true").getSingleResult();When to use saveAndFlush: when you need a DB-generated ID or column immediately in the same transaction; when a native query must see just-saved data.