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

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

1.7 Middle🔥 161 комментариев
#ORM и Hibernate

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

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

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

Ответ: Как ведет себя load() в Hibernate, если объект отсутствует?

Метод load() в Hibernate работает не так, как get(). Когда объект не найден в БД, load() выбрасывает исключение ObjectNotFoundException, в то время как get() просто возвращает null.

Различие между load() и get():

public class User {
    @Id
    private Long id;
    private String name;
}

// Используем Session
Session session = sessionFactory.openSession();

// Сценарий: пытаемся загрузить User с id = 999 (не существует)

// Способ 1: load()
try {
    User user = session.load(User.class, 999L);
    // load() НЕ проверяет наличие в БД сразу!
    // Возвращает proxy объект
    
    // Исключение выбросится только при обращении к полям объекта
    System.out.println(user.getName());  // <- HERE ObjectNotFoundException!
} catch (ObjectNotFoundException e) {
    System.out.println("User not found: " + e.getMessage());
}

// Способ 2: get()
User user = session.get(User.class, 999L);
if (user == null) {
    System.out.println("User not found");  // просто null, исключение не выбросится
}

Поведение load():

1. load() возвращает proxy (заместитель)

User user = session.load(User.class, 999L);

// На этом этапе:
// - Объект load() уже вернул
// - Никакого SQL запроса в БД нет!
// - Это объект-заместитель (proxy)
// - Exception ещё не выбросилось

System.out.println(user.getClass().getName());
// Выведет: User$HibernateProxy$... (не просто User)

2. Exception выбросится при обращении к полям

User user = session.load(User.class, 999L);  // OK, возвращает proxy

// Попытка обращения к полям триггирует инициализацию
try {
    String name = user.getName();  // <- SQL запрос в БД
                                    // <- ObjectNotFoundException!
} catch (ObjectNotFoundException e) {
    System.out.println("Caught: " + e.getClass().getName());
    // org.hibernate.ObjectNotFoundException
}

Полный пример с разными сценариями:

public class HibernateLoadDemo {
    
    public static void demonstrateLoad(Session session) {
        
        // Сценарий 1: объект существует
        System.out.println("\n=== Сценарий 1: объект существует ===");
        User existing = session.load(User.class, 1L);
        // load() вернул proxy
        System.out.println(existing.getClass());  // User$HibernateProxy
        System.out.println(existing.getName());   // SELECT * FROM users WHERE id = 1
        // Теперь он инициализирован
        System.out.println(existing.getName());   // нет SQL запроса, используется кэш
        
        // Сценарий 2: объект не существует
        System.out.println("\n=== Сценарий 2: объект не существует ===");
        try {
            User missing = session.load(User.class, 999L);
            System.out.println("Загружен: " + missing.getClass());
            // На этом этапе SQL ещё не было!
            
            // При обращении к полю — исключение
            System.out.println("Имя: " + missing.getName());
        } catch (ObjectNotFoundException e) {
            System.out.println("ObjectNotFoundException: " + e.getMessage());
        }
    }
    
    public static void demonstrateGet(Session session) {
        
        // Сценарий 1: объект существует
        System.out.println("\n=== get() - объект существует ===");
        User existing = session.get(User.class, 1L);
        // Сразу выполняется SELECT
        System.out.println(existing.getClass());  // User (не proxy!)
        System.out.println(existing.getName());   // уже в памяти
        
        // Сценарий 2: объект не существует
        System.out.println("\n=== get() - объект не существует ===");
        User missing = session.get(User.class, 999L);
        // get() выполняет SELECT и если нет результата — возвращает null
        if (missing == null) {
            System.out.println("get() вернул: null");
        } else {
            System.out.println(missing.getName());
        }
    }
}

ObjectNotFoundException: что это?

import org.hibernate.ObjectNotFoundException;

// ObjectNotFoundException выбросится в следующих случаях:

try {
    User user = session.load(User.class, 999L);
    
    // При обращении к любому property (кроме id)
    user.getName();           // <- ObjectNotFoundException
    user.getEmail();          // <- ObjectNotFoundException
    user.toString();          // <- ObjectNotFoundException (если переопределён)
    
    // Обращение к id обычно не вызывает исключение
    Long id = user.getId();   // обычно OK
    
} catch (ObjectNotFoundException e) {
    // Сообщение об ошибке
    System.out.println(e.getMessage());
    // Например: "Unable to find User with id 999"
    
    // Можно получить детали
    System.out.println(e.getIdentifier());     // 999
    System.out.println(e.getEntityName());     // User
}

Использование load() vs get():

// Когда использовать load():
public void updateUser(Long id, String newName) {
    User user = session.load(User.class, id);
    // Гарантированно знаем, что существует
    // или хотим, чтобы выбросилось исключение
    user.setName(newName);
    session.save(user);
    // load() экономит SQL query если объект только для обновления
}

// Когда использовать get():
public User getUserInfo(Long id) {
    User user = session.get(User.class, id);
    if (user == null) {
        return null;  // мягкая обработка отсутствия
    }
    return user;
}

Исключение в контексте Transaction:

@Transactional
public void processUser(Long id) {
    try {
        User user = session.load(User.class, id);
        user.setName("Updated");  // <- ObjectNotFoundException может выброситься здесь
        // session.save() сохраняет в памяти
    } catch (ObjectNotFoundException e) {
        // Transaction будет помечена как rolled back
        throw e;  // пробросим дальше
    }
    // В конце метода транзакция автоматически закоммитится (если нет ошибок)
}

Lazy Loading и load():

public class Department {
    @Id
    private Long id;
    
    @OneToMany(mappedBy = "department", fetch = FetchType.LAZY)
    private Set<User> users;
}

// load() часто используется для LAZY отношений
Department dept = session.load(Department.class, 1L);

// Коллекция users ещё не загружена
dept.getUsers().size();  // SELECT COUNT(*) FROM users WHERE dept_id = 1

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

Опция              | load()                | get()
-------------------|----------------------|----------------------
Возвращаемое       | Proxy объект          | Реальный объект
SQL при вызове     | НЕТ                  | ДА
Отсутствие объекта | ObjectNotFoundException| null
Время выполнения   | Быстро (O(1))        | Зависит от SELECT
Применение         | Обновления, удаления | Чтение данных

Исключение в старых версиях Hibernate:

// Hibernat 2.x, 3.x выбрасывали просто Exception
try {
    User user = session.load(User.class, 999L);
    user.getName();
} catch (ObjectNotFoundException e) {  // более специфичное
    // обработка
}

// Иногда нужно ловить родительский класс
catch (Exception e) {
    // ловит любые ошибки
}

Практический совет:

// Вместо
User user = session.load(User.class, id);
try {
    user.getName();
} catch (ObjectNotFoundException e) {
    // ошибка
}

// Лучше сразу использовать get()
User user = session.get(User.class, id);
if (user != null) {
    String name = user.getName();
}

// Или с Optional (JPA)
Optional<User> user = userRepository.findById(id);
user.ifPresent(u -> processUser(u));

Заключение:

load():

  • Возвращает proxy (заместитель) объект сразу
  • Не выполняет SQL запрос при вызове
  • Выбросит ObjectNotFoundException при доступе к полям если объект не существует
  • Эффективен когда объект нужен только для обновления

get():

  • Возвращает реальный объект или null
  • Выполняет SQL запрос немедленно
  • Более предсказуем и часто безопаснее
  • Рекомендуется для чтения данных

Выбор между ними зависит от случая использования и требований приложения к обработке ошибок.

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