Как правильно очистить Hibernate Session - PullRequest
0 голосов
/ 28 января 2012

Я использую Hibernate в своем приложении и заметил, что всякий раз, когда выдается ошибка Hibernate, приложение в конечном итоге вылетает с ошибками, связанными с БД.Из того, что я прочитал, проблема в том, что сеанс Hibernate находится в каком-то неиспользуемом состоянии, и поэтому его необходимо отбросить.Однако он возвращается в пул и повторно используется при следующем вызове, а не сбрасывается.

Как правильно при запуске каждой функции гарантировать, что сеанс пригоден для использованияи, если нет, чтобы убедиться, что он сброшен правильно и новый сеанс запущен?

Мой конфигурационный файл Hibernate включает в себя следующее:

<property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">10</property>
<property name="hibernate.c3p0.timeout">60</property>
<property name="hibernate.c3p0.idle_test_period">45</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.preferredTestQuery">SELECT 1;</property>
<property name="hibernate.c3p0.testConnectionOnCheckout">true</property>
<property name="hibernate.c3p0.acquireRetryAttempts">3</property>

и мой код с этой ошибкой (завершеновызовы функций):

public static ReturnCodes newUser(Long id, String username, String country) {

    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    Transaction transaction = null;
    try {
        transaction = session.beginTransaction();

        //check for duplicate user
        User checkUser = getUserByExternalID(id, true);
        if (checkUser != null && checkUser.getId().intValue() == id.intValue()) {
            transaction.commit();
            return ReturnCodes.DUPLICATE;
        }

        User newUser = new User();
        newUser.setUsername(username);
        newUser.setExternalID(id);
        newUser.setCountry(country);

        session.save(newUser);
        transaction.commit();
        return ReturnCodes.SUCCESS;
    } catch (ConstraintViolationException e) {
        log.info("The user must already exists, so cleanup and return DUPLICATE.");
        return ReturnCodes.DUPLICATE;
    } catch (Exception e) {
        log.info("An unknown error occurred, so cleanup and return GENERAL FAILURE.");
        return ReturnCodes.GENERAL_FAILURE;
    }
}
public static User getUserByExternalID(Long userid, boolean leaveTransaction) {
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    User user = null;
    try {
        session.beginTransaction();
        Criteria c = session.createCriteria(User.class);
        c.add(Restrictions.eq("externalID", userid));
        user = (User)c.uniqueResult();
        if (!leaveTransaction)
            session.getTransaction().commit();
    } catch (Exception e) {
        log.error("Could not retrieve user with External ID " + userid, e);
    }
    return user;
}

Ответы [ 3 ]

1 голос
/ 28 января 2012

Наиболее распространенным подходом является управление транзакциями и сеансами Hibernate в службах, уровень выше DAO.В этом случае вы можете выполнить несколько операций с базой данных в одной транзакции.Например, в вашем случае вы можете явно проверить, существует ли пользователь с данным именем пользователя, прежде чем пытаться создать нового.Таким образом, вы можете позволить Hibernate обрабатывать все SQLExceptions и преобразовывать их в исключение времени выполнения.

Обычно это делается путем внедрения кода управления транзакциями через библиотеку внедрения зависимостей.Самая популярная библиотека DI - Spring.

1 голос
/ 28 января 2012

Управление сеансами и транзакциями немного сложное.

Spring реализовал это, аннотируя методы с помощью @Transactional.

Если вы хотите обработать это вручную, прочитайте это . Вы можете использовать Filter для запуска сеанса или некоторый прокси и ThreadLocal. Чаще всего сеанс создается для каждого запроса.

0 голосов
/ 29 января 2012

В итоге я добавил следующую строку в каждый блок catch:

session.clear();

, который, согласно документации,

Полностью очистить сеанс.Исключите все загруженные экземпляры и отмените все ожидающие сохранения, обновления и удаления.Не закрывайте открытые итераторы или экземпляры ScrollableResults.

Результатом этого является то, что сеанс возвращается в работоспособное состояние, и последующее использование того же сеанса не будет затронуто предыдущей ошибкой.

Это, конечно, не решает каких-либо проблем, связанных с надлежащим разграничением объема транзакций, что, как правильно объясняют Олаф и Божо, лучше всего обрабатывать вне области какого-либо конкретного DAO.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...