← Назад к вопросам

Как ведет себя get() в Hibernate, если объект отсутствует

2.0 Middle🔥 171 комментариев
#ORM и Hibernate#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Поведение get() в Hibernate при отсутствии объекта

EntityManager.getReference() vs session.get()

В Hibernate существует важное различие между двумя методами для получения объекта по ID:

1. session.get() — Возвращает null

// Hibernate Session API (старый стиль)
Session session = sessionFactory.openSession();
User user = session.get(User.class, 99L);  // Если не найдено
// user == null

Метод get() возвращает null если объект с заданным ID не существует в базе данных. Это безопасный способ проверить наличие объекта.

Session session = sessionFactory.openSession();
User user = session.get(User.class, userId);

if (user != null) {
    System.out.println("Пользователь найден: " + user.getName());
} else {
    System.out.println("Пользователь не найден");
}

2. EntityManager.getReference() — Выбрасывает исключение

// JPA API (современный стиль)
EntityManager em = entityManagerFactory.createEntityManager();

try {
    User user = em.getReference(User.class, 99L);
    // Если не найдено — EntityNotFoundException!
} catch (EntityNotFoundException e) {
    System.out.println("Объект не найден");
}

Метод getReference() выбрасывает EntityNotFoundException, если объект не существует. Важно: исключение выбрасывается не сразу, а при обращении к полям объекта!

3. JpaRepository.getById() — Отложенная ошибка

// Spring Data JPA
@Repository
public interface UserRepository extends JpaRepository<User, Long> {}

// Использование
User user = userRepository.getById(99L);  // Не выбрасывает исключение сразу!
System.out.println(user.getName());  // EntityNotFoundException выбросится здесь!

getById() возвращает прокси-объект Hibernate, но исключение выбрасывается только при первом обращении к его полям (lazy loading).

4. JpaRepository.findById() — Безопасный вариант

// Рекомендуемый подход
Optional<User> user = userRepository.findById(99L);

if (user.isPresent()) {
    System.out.println("Найден: " + user.get().getName());
} else {
    System.out.println("Не найден");
}

// Или более компактно
user.ifPresentOrElse(
    u -> System.out.println("Найден: " + u.getName()),
    () -> System.out.println("Не найден")
);

// Или с get()
User user = userRepository.findById(99L)
    .orElseThrow(() -> new NotFoundException("User not found"));

findById() возвращает Optional — это самый безопасный и явный способ.

Сравнительная таблица

Метод                   | Не найдено        | Когда выбросит
------------------------|-------------------|------------------
session.get()           | null              | Никогда
EntityManager.get()     | null              | Никогда
EntityManager.getRef()  | Прокси            | При обращении
session.load()          | Прокси            | При обращении
getById() (Spring)      | Прокси            | При обращении
findById() (Spring)     | Optional.empty()  | Никогда

Практический пример: обработка ошибок

@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository repository;
    
    // Вариант 1: Возвращаем DTO или null
    public UserDto getUserOrNull(Long id) {
        return repository.findById(id)
            .map(this::toDto)
            .orElse(null);
    }
    
    // Вариант 2: Выбрасываем исключение (предпочтительно)
    public UserDto getUserOrThrow(Long id) {
        return repository.findById(id)
            .map(this::toDto)
            .orElseThrow(() -> new UserNotFoundException(
                "User with id " + id + " not found"
            ));
    }
    
    // Вариант 3: Устанавливаем default значение
    public UserDto getUserOrDefault(Long id) {
        return repository.findById(id)
            .map(this::toDto)
            .orElseGet(() -> UserDto.anonymous());
    }
    
    private UserDto toDto(User user) {
        return new UserDto(user.getId(), user.getName());
    }
}

Ошибки, которых нужно избегать

// ❌ ОПАСНО: LazyInitializationException
User user = userRepository.getById(id);
// сессия закрывается
Session session = em.unwrap(Session.class);
session.close();
// Теперь попытка доступа выбросит исключение!
System.out.println(user.getName());

// ✅ ПРАВИЛЬНО: Используй findById с Optional
Optional<User> user = userRepository.findById(id);
if (user.isPresent()) {
    System.out.println(user.get().getName());
}

Рекомендации

  • Используй findById() с Optional — это явно и безопасно
  • Избегай getById() — отложенное выбрасывание исключения опасно
  • Используй get() только когда нужен null — редкий случай
  • Всегда обрабатывай отсутствие объекта явно через Optional или try-catch
  • Выбрасывай кастомные исключения если объект должен существовать
Как ведет себя get() в Hibernate, если объект отсутствует | PrepBro