Массовое обновление Hibernate с использованием ScrollableResult закрывается при фиксации

Мы хотим изменить объемные данные, используя сеанс без сохранения состояния hibernate 5.2 и некоторый код, подобный этому:

    Transaction transaction = session.getTransaction();

    Query q = session.createQuery("from " + MyClass.class.getName());
    ScrollableResults scroll = q.scroll(ScrollMode.SCROLL_INSENSITIVE);

    int cnt = 0;
    while (scroll.next()) {
        MyClass obj = (MyClass) scoll.get(0);
        // modify obj
        session.update(obj);
        if (++cnt % batchSize == 0)
            transaction.commit();
    }

    transaction.commit();

Фиксация - это обычно каждые 1k объектов, так как полная таблица огромна. Использование hibernate 4 вышеупомянутый код работал в течение многих лет. Однако в hibernate 5.2.7 мы получаем следующую трассировку стека:

org.hibernate.exception.GenericJDBCException: could not advance using next()
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:97)
    at org.hibernate.internal.ScrollableResultsImpl.convert(ScrollableResultsImpl.java:69)
    at org.hibernate.internal.ScrollableResultsImpl.next(ScrollableResultsImpl.java:104)
Caused by: java.sql.SQLException: You can't operate on a closed ResultSet!!!
    at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:118)
    at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:77)
    at com.mchange.v2.c3p0.impl.NewProxyResultSet.next(NewProxyResultSet.java:691)
    at org.hibernate.internal.ScrollableResultsImpl.next(ScrollableResultsImpl.java:99)
    ... 4 more
Caused by: java.lang.NullPointerException
    at com.mchange.v2.c3p0.impl.NewProxyResultSet.next(NewProxyResultSet.java:685)
    ... 5 more

Причина в том, что ScrollableResults закрывается при фиксации. Это, кажется, предполагаемое поведение, так как:

http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html

"Если приложение не будет закрыто, Hibernate автоматически закроет базовые ресурсы (например, ResultSet и PreparedStatement), используемые внутри ScrollableResults, когда текущая транзакция будет завершена (фиксация или откат). Однако рекомендуется закрывать ScrollableResults явным образом. ".

Лучшее решение, кажется, открыть второй сеанс (и соединение), как это:

    StatelessSession session = sessionFactory.openStatelessSession();
    StatelessSession sessionCursor = sessionFactory.openStatelessSession();

    Transaction transaction = session.getTransaction();

    Query q = sessionCursor.createQuery("from " + MyClass.class.getName());
    ScrollableResults scroll = q.scroll(ScrollMode.SCROLL_INSENSITIVE);

    int cnt = 0;
    while (scroll.next()) {
        MyClass obj = (MyClass) scoll.get(0);
        // modify obj
        session.update(obj);
        if (++cnt % batchSize == 0)
            transaction.commit();
    }

    transaction.commit();

Это действительно лучшее решение? Интересно, как другие люди обновляют большой набор данных, используя прокручиваемый результат?

0 ответов

Другие вопросы по тегам