Ответ
Сессия (org.hibernate.Session) — это центральный, короткоживущий объект в Hibernate, который представляет собой обертку вокруг JDBC-соединения и является точкой входа для выполнения операций с базой данных. Это не потокобезопасный объект, который обычно ассоциируется с одним запросом или транзакцией (паттерн "session-per-request").
Ключевые обязанности Session
- Кэш первого уровня (L1 Cache): Каждая сессия имеет свой собственный кэш объектов. Повторные обращения к одному и тому же объекту в рамках одной сессии не вызывают лишних SQL-запросов.
- Управление жизненным циклом объектов: Сессия отслеживает состояние объектов (transient, persistent, detached, removed).
- Координация запросов: Преобразует операции с объектами (save, update) в SQL-запросы.
- Обеспечение ленивой загрузки (Lazy Loading): Позволяет отложенно загружать связанные коллекции и прокси-объекты.
Пример типичного использования
// Получение сессии из фабрики (обычно через ThreadLocal)
Session session = sessionFactory.openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
// CRUD операции
User newUser = new User("Alice"); // Transient state
session.save(newUser); // Persistent state, INSERT запланирован
User user = session.get(User.class, 1L); // SELECT, объект закеширован в L1
user.setName("Bob"); // UPDATE запланирован (изменение отслеживается)
session.delete(user); // DELETE запланирован
transaction.commit(); // Все запросы выполняются здесь
// После commit/close объект становится detached
System.out.println(newUser.getId()); // ID доступен после сохранения
} catch (Exception e) {
if (transaction != null) transaction.rollback();
throw e;
} finally {
session.close(); // Критически важно закрывать сессию!
}
Важные принципы работы
- Короткий срок жизни: Сессия должна открываться непосредственно перед операцией и закрываться сразу после. Не храните ее открытой.
- Не потокобезопасна: Никогда не используйте одну сессию в нескольких потоках.
- Связь с транзакцией: Границы сессии и транзакции часто совпадают, но это не обязательно.
- Отсоединенные объекты (Detached): После
session.close()илиsession.evict()объекты становятся detached. Их изменения не отслеживаются, для повторного сохранения нуженsession.update()илиsession.merge().
Ответ 18+ 🔞
А, слушай-ка, про эту вашу сессию в Хибернейте. Ну, это ж, блядь, как главный дирижёр в оркестре из SQL-запросов, только живёт он, как мотылёк — один запрос и нахуй. Обёртка вокруг соединения с базой, короче. И главное — с ней в нескольких потоках нельзя, она не потокобезопасная, сука! Одна сессия — один запрос, паттерн такой, session-per-request, запомни.
Чем она, эта манда с ушами, занимается?
- Кэш свой, блядь, первый уровень. У каждой сессии свой личный закуток в памяти, куда она складывает объекты. Спросил один раз пользователя — она тебе его из базы вытащила и в закуток положила. Спросишь второй раз в этой же сессии — она тебе из закутка подаст, SQL-то новый не пойдёт. Удобно, ёпта!
- За объектами следит, как наседка. Она знает, в каком они состоянии: только созданный (transient), уже привязанный к базе (persistent), отвязанный (detached) или на удаление (removed). Вся эта хуйня.
- Переводит с языка объектов на язык SQL. Сказал ей
session.save(newUser)— она в уме уже строчитINSERT INTO users .... Хитрая жопа. - Ленивую загрузку обеспечивает. Это когда связанные коллекции грузятся не сразу, а только когда ты к ним полез. Чтобы не тащить овердохуища данных просто так.
Вот как это обычно выглядит в коде, смотри:
// Достаём сессию из фабрики (обычно её через ThreadLocal прячут)
Session session = sessionFactory.openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
// CRUD операции, вся наша работа тут
User newUser = new User("Alice"); // Это transient, база про него не знает
session.save(newUser); // А теперь persistent! INSERT запланирован
User user = session.get(User.class, 1L); // SELECT, объект теперь в кэше L1
user.setName("Bob"); // Ёбаный UPDATE запланирован, сессия же следит!
session.delete(user); // Ну и DELETE, ясное дело
transaction.commit(); // И вот тут, блядь, ВСЕ запланированные запросы полетели в базу!
// После commit или close объект становится detached, отвязанным
System.out.println(newUser.getId()); // ID появится только после сохранения, логично
} catch (Exception e) {
if (transaction != null) transaction.rollback(); // Откатываемся, если пиздец
throw e;
} finally {
session.close(); // ЗАКРЫТЬ, БЛЯДЬ, ОБЯЗАТЕЛЬНО! Не оставляй её висеть!
}
А теперь главные правила, чтобы не обосраться:
- Живёт недолго. Открыл — сделал дело — закрыл. Не таскай её с собой, как любимую игрушку.
- Не для всех потоков. Одна сессия — один поток. Иначе будет race condition и прочий пиздец.
- Часто с транзакцией за ручку. Границы сессии и транзакции обычно совпадают, но не всегда, это тонкость.
- Отвязанные объекты (Detached). После
session.close()илиsession.evict()объекты становятся как сироты — detached. Их изменения уже не отслеживаются. Хочешь обратно в базу — делайsession.update()илиsession.merge(). Вот такая, блядь, магия.