Подтвердить что ты не робот

Org.hibernate.Session.clear() считается вредным?

Это вопрос дизайна, конкретный код не представлен для защиты моего основания.

При работе с Hibernate стандартный рабочий процесс выглядит следующим образом:

  • Открыть сеанс
  • Запустить транзакцию
  • Сделайте бизнес (прочитайте и измените данные)
  • Commit Transaction
  • Закрытие сеанса

с возможными итерациями через 2-4.

Каковы разумные варианты использования Session.clear()?

A: Конкретная проблема, с которой я столкнулся, - это (большая) часть кода, которая загружает и изменяет сущности, а затем очищает() s сеанс, существенно отбрасывая сделанные изменения. (Деловая задача, которая должна быть выполнена, не включает в себя модификацию объектов, поэтому код "работает" ).

Кажется, что правильным дизайном было бы удостовериться, что (большая) часть кода не вносит изменений, которые он не хочет сохранять?

B: Я бы предположил, что Session.clear() существует для удобства/гибкости, а не потому, что это хорошая идея использовать его.

Я неправильно понял философию гиберната?

C: Subquestion: это плохая идея для кода фрейма безоговорочно очистить() сеанс, когда задача завершается? IMHO, структура должна жаловаться, если сеанс грязный, когда задача завершается! Сессия должна быть закрыта, поскольку задача выполняется... (без учета производительности за минуту)

(Ярлыки A, B и C, чтобы вы могли указать, какую часть вы отвечаете).

4b9b3361

Ответ 1

Ad. A: Похоже, вы знаете, что делает clear(). Причина явного обращения к нему - удалить все управляемые объекты из кеша L1, чтобы он не увеличивался бесконечно при обработке больших наборов данных в одной транзакции.

Отбрасывает все изменения, которые были внесены в управляемые entites , явно не сохраняемые. Это означает, что вы можете безопасно модифицировать объект, обновить его явно и очистить сеанс. Это правильный дизайн. Очевидно, что если никаких изменений не сделано (длинный, но сеанс только для чтения), clear() всегда безопасен.

Вы также можете использовать сеансы без сохранения состояния.

Ad. B: Нет, он существует по причинам выше: чтобы убедиться, что L1 (кеш сеанса) не растет слишком сильно. Конечно, поддерживать его вручную - это плохая идея и указание на то, что для больших наборов данных следует использовать другой инструмент, но иногда это необходимо.

Обратите внимание, что в спецификации JPA также есть метод clear() и flush(). В этом случае вы всегда должны сначала вызвать flush(), чтобы вносить изменения в базу данных (явное обновление) до вызова clear().

Ad. C. Это действительно хорошая идея, чтобы предупредить пользователя (возможно, выпустив предупреждающее сообщение, а не бросая исключение), когда он очищает сеанс грязными изменениями. Кроме того, я не думаю, что код фрейма должен безоговорочно вызывать clear(), если он не уверен, что код пользователя, который он запускает, сбрасывает или не вносит никаких изменений.

Ответ 2

Вот еще одна причина, по которой я только что столкнулся: кеширование предыдущих результатов при вызове хранимой процедуры несколько раз в рамках одной транзакции. Упрощенный код следующим образом.

//Begin transaction
SessionFactory sf = HibernateSessionFactory.getFactory();
Session dbSession = sf.getCurrentSession();
dbSession.beginTransaction();

//First call to stored procedure
Query query = dbSession.getNamedQuery("RR_CUST_OPP_DATA");
query.setString("custName", "A");
List<ShipSummaryRow> shipSummaryRows = query.list();

//Second call to stored procedure
Query query = dbSession.getNamedQuery("RR_CUST_OPP_DATA");
query.setString("custName", "B");
List<ShipSummaryRow> shipSummaryRows = query.list();

//Commit both    
dbSession.getTransaction().commit();

Без clear() после первого вызова строки результатов первого вызова реплицируются в набор результатов второго вызова. Я использую Oracle 11gR2.

Ключом к репликации этой ошибки является выполнение обоих вызовов в рамках одной транзакции. Поскольку я использую шаблон открытого сеанса в представлении, оба вызова автоматически происходят в одной транзакции (так как исходный код вызывает proc в цикле, сохраняя результаты каждого из них). Поэтому я называю это ошибкой; иначе можно было бы рассмотреть функцию, но даже тогда clear() не вызывается в образцах кода, заявляя, что он должен быть вызван. session.flush() ничего не делал. Отображение файла, как показано ниже. В результате я добавил clear() в конец всех моих вызовов процедур. Я еще не тестировал свои собственные вызовы SQL. Это тривиальный материал; удивлен, что ошибка существует.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.jfx.rr.model.ShipSummaryRow">
        <id name="id" type="integer"/>
        <property name="shipQtrString" not-null="true" type="string"/>
        <property name="shipAmount" not-null="true" type="double"/>
    </class>
    <sql-query callable="true" name="RR_CUST_OPP_DATA">
        <return class="com.jfx.rr.model.ShipSummaryRow">
            <return-property column="SHIPPED_ID" name="id"/>
            <return-property column="SHIP_QTR" name="shipQtrString"/>
            <return-property column="SHIPPED_AMOUNT" name="shipAmount"/>
        </return>
        { call RR_DASHBOARD_REPORTS_PKG.RR_CUST_OPP_DATA(?, :custName) }
    </sql-query>
</hibernate-mapping>