Попадет ли сущность в кэш первого уровня при вызове save
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Попадёт ли сущность в кэш первого уровня при вызове save?
Да, сущность попадёт в кэш первого уровня (First-Level Cache, Session Cache) при вызове метода save() в Hibernate/JPA.
Что такое кэш первого уровня
Кэш первого уровня — это механизм кэширования, встроенный в persistence context (Session в Hibernate или EntityManager в JPA). Он существует на уровне сессии/транзакции и автоматически управляется Hibernate.
Как это работает
@Service
@Transactional
public class UserService {
@Autowired
private EntityManager em;
public void saveAndRetrieveUser() {
User user = new User();
user.setName("John");
// 1. Вызываем save() - сущность попадает в кэш первого уровня
em.persist(user); // или repository.save(user)
// 2. На этом этапе сущность уже в кэше первого уровня
// Её id может быть ещё null (зависит от стратегии генерации)
// 3. Вторичный поиск из кэша, БД не затронута
User retrieved = em.find(User.class, user.getId());
// Или через JPQL
Query query = em.createQuery("SELECT u FROM User u WHERE u.id = :id");
query.setParameter("id", user.getId());
User found = (User) query.getSingleResult();
// retrieved == found == user (один объект!)
}
}
Жизненный цикл при save
Этап 1: Transient (новая сущность)
User user = new User();
user.setName("John");
// Объект существует только в памяти, в кэше нет
Этап 2: Persist/Save (добавление в кэш)
em.persist(user); // или userRepository.save(user)
// Объект переходит в состояние Managed
// Попадает в кэш первого уровня (persistence context)
// SQL INSERT ещё не выполнен
Этап 3: В кэше, ждёт flush
// Объект в памяти и в кэше, но SQL ещё не отправлен в БД
User same = em.find(User.class, user.getId()); // Из кэша
Этап 4: Flush и commit
// При завершении транзакции происходит flush
// SQL INSERT выполняется в этот момент
// После commit объект остаётся Managed до закрытия сессии
Доказательство через пример
@Service
public class CacheTest {
@Autowired
private EntityManager em;
@Autowired
private UserRepository userRepository;
@Transactional
public void demonstrateFirstLevelCache() {
User user = new User("Alice");
// 1. Сохраняем
User saved = userRepository.save(user);
System.out.println("User ID after save: " + saved.getId());
// ID может быть null в зависимости от GenerationType
// 2. Получаем из БД - на самом деле из кэша
User found = userRepository.findById(saved.getId()).orElse(null);
// 3. Это один и тот же объект
System.out.println(saved == found); // true - один объект из кэша!
// 4. Меняем имя
saved.setName("Bob");
// 5. Выполняем UPDATE БД - нужно вызвать flush или saveAndFlush
userRepository.saveAndFlush(saved);
// Теперь в БД имя Bob, и объект всё ещё в кэше первого уровня
}
}
Важные моменты
Identity vs Equality Oбъекты, вернутые из кэша первого уровня, — один и тот же объект (identity), не копия.
User u1 = repository.save(user);
User u2 = repository.findById(user.getId()).orElse(null);
u1 == u2 // true, один объект
u1.equals(u2) // true
GenerationType влияет на ID
@GeneratedValue(strategy = GenerationType.IDENTITY)
// ID генерируется БД, поэтому fill происходит при flush
@GeneratedValue(strategy = GenerationType.SEQUENCE)
// ID генерируется до сохранения, доступен сразу
Scope кэша первого уровня Кэш существует в рамках persistence context (обычно = одна транзакция).
@Transactional
public void method1() {
User u = repository.save(user);
// В кэше первого уровня
}
// После завершения транзакции persistence context закрывается
// Кэш первого уровня очищается
public void method2() {
// Новая транзакция = новый persistence context = новый кэш
User u = repository.findById(id);
// Будет запрос к БД, кэша нет
}
Отличие от кэша второго уровня (L2 Cache)
Кэш первого уровня:
- Встроенный, всегда работает
- Уровень сессии/транзакции
- Управляется автоматически
- Scope: EntityManager/Session
Кэш второго уровня (L2 Cache):
- Опциональный (нужно подключать)
- Уровень SessionFactory (приложения)
- Требует конфигурации (Ehcache, Redis)
- Scope: всё приложение
// L2 Cache нужно явно включить
@Cacheable
@Entity
public class User { ... }
Вывод
Да, сущность обязательно попадёт в кэш первого уровня при вызове save()/persist(). Это автоматический механизм Hibernate/JPA, который повышает производительность, избегая повторных запросов к БД в рамках одной транзакции.