JSR-352 с профилем Liberty — «ORA-01002: выборка вне последовательности»

Я экспериментирую с реализацией JSR-352 в профиле Liberty и был поставлен в тупик ошибкой «ORA-01002: выборка вне последовательности» после того, как мой читатель обработает первые 10 элементов моего JDBC ResultSet. Размер моего фрагмента установлен на 100.

Вот мой читатель:

@Dependent
@Named("myItemReader")
public class MyItemReader extends AbstractItemReader {

    @Resource(name="jdbc/somedb",shareable=false)
    private DataSource lavDb;

    private PreparedStatement stmt;
    private ResultSet rs;

    @Override
    public void open(Serializable checkpoint) throws Exception {
        Connection con = lavDb.getConnection();
        con.setAutoCommit(false);
        stmt = con.prepareStatement("select id from sometable",
               ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
        rs = stmt.executeQuery();
    }

    @Override
    public MyInputRecord readItem() throws Exception{
        if(rs.next()){
            return new MyInputRecord(rs.getInt(1));
        }
        return null;
    }

    @Override
    public void close(){
        try{
            rs.close();
            stmt.close();
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }
}

Если обработка ResultSet происходит в методе open(), то я не сталкиваюсь с какими-либо ошибками.

Вот моя конфигурация batchPersistence из моего server.xml:

<dataSource id="oracle-wasadmin" jdbcDriverRef="wasoracledriver" jndiName="jdbc/wasoracledb" type="javax.sql.XADataSource">
    <properties.oracle URL="${wasadmin.jdbcurl}" password="xxxxxx" user="yyyyyy"/>
    <conionManager agedTimeout="1m" maxIdleTime="15m" maxPoolSize="25" minPoolSize="0"/>
</dataSource>

<jdbcDriver id="wasoracledriver" javax.sql.XADataSource="oracle.jdbc.xa.client.OracleXADataSource">
    <library>
        <fileset dir="${shared.resource.dir}/oracle" includes="*.jar"/>
    </library>
</jdbcDriver>

Here is the error in the joblog:

com.ibm.jbatch.container.exception.BatchContainerRuntimeException: Failure in Read-Process-Write Loop
    at com.ibm.jbatch.container.controller.impl.ChunkStepControllerImpl.invokeChunk(ChunkStepControllerImpl.java:702)
    at com.ibm.jbatch.container.controller.impl.ChunkStepControllerImpl.invokeCoreStep(ChunkStepControllerImpl.java:792)
    at com.ibm.jbatch.container.controller.impl.BaseStepControllerImpl.execute(BaseStepControllerImpl.java:292)
    at com.ibm.jbatch.container.controller.impl.ExecutionTransitioner.doExecutionLoop(ExecutionTransitioner.java:118)
    at com.ibm.jbatch.container.controller.impl.WorkUnitThreadControllerImpl.executeCoreTransitionLoop(WorkUnitThreadControllerImpl.java:94)
    at com.ibm.jbatch.container.controller.impl.WorkUnitThreadControllerImpl.executeWorkUnit(WorkUnitThreadControllerImpl.java:155)
    at com.ibm.jbatch.container.controller.impl.WorkUnitThreadControllerImpl$AbstractControllerHelper.runExecutionOnThread(WorkUnitThreadControllerImpl.java:480)
    at com.ibm.jbatch.container.controller.impl.WorkUnitThreadControllerImpl.runExecutionOnThread(WorkUnitThreadControllerImpl.java:90)
    at com.ibm.jbatch.container.util.BatchWorkUnit.run(BatchWorkUnit.java:117)
    at com.ibm.ws.context.service.serializable.ContextualRunnable.run(ContextualRunnable.java:80)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
Caused by: com.ibm.jbatch.container.exception.BatchContainerRuntimeException: java.sql.SQLException: ORA-01002: fetch out of sequence

    at com.ibm.jbatch.container.controller.impl.ChunkStepControllerImpl.readItem(ChunkStepControllerImpl.java:354)
    at com.ibm.jbatch.container.controller.impl.ChunkStepControllerImpl.readAndProcess(ChunkStepControllerImpl.java:245)
    at com.ibm.jbatch.container.controller.impl.ChunkStepControllerImpl.invokeChunk(ChunkStepControllerImpl.java:626)
    ... 14 more
Caused by: java.sql.SQLException: ORA-01002: fetch out of sequence

У меня есть дополнительные журналы и т. д., если они будут полезны. Заранее спасибо.


person Colby Montgomery    schedule 15.02.2017    source источник
comment
Хотя это и не относится к вашему исключению, я предполагаю, что conionManager в вашем server.xml является опечаткой?   -  person F Rowe    schedule 15.02.2017
comment
Да, это опечатка в сообщении, server.xml имеет правильное значение.   -  person Colby Montgomery    schedule 15.02.2017
comment
Пробовали ли вы добавить флаг ResultSet.HOLD_CURSORS_OVER_COMMIT к другим в свой prepareStatement?   -  person Scott Kurz    schedule 16.02.2017
comment
Попытался изменить prepareStatmemt на stmt = con.prepareStatement("select id from sometable", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT); ORA-01002 по-прежнему сохраняется. Если я добавлю stmt.setFetchSize(100000);, моя работа будет завершена.   -  person Colby Montgomery    schedule 16.02.2017
comment
Кажется странным, что это работает для 10 предметов. Я знаю, что вы сказали, что размер вашего фрагмента равен 100, но мне интересно, есть ли способ, которым вы могли бы в любом случае получить размер фрагмента 10. Можете ли вы вставить свой фрагмент JSL (XML), который показывает определение шага фрагмента?   -  person Scott Kurz    schedule 16.02.2017
comment
Итак, вы действительно используете размер фрагмента 100. Тот факт, что setFetchSize имеет значение, предполагает, что это не принципиально пакетный вопрос, а более общий вопрос Oracle JDBC (включая любую конфигурацию по умолчанию, которая может применяться в Liberty). Как вы заметили, это распространенный шаблон в пакетном режиме ... но на данный момент я буду спокоен и посмотрю, может ли кто-нибудь с большим опытом работы с Oracle ответить. Еще одна вещь... как упоминалось ниже @njr, обязательно закройте соединение в close()!   -  person Scott Kurz    schedule 16.02.2017


Ответы (1)


Не кэшируйте экземпляры JDBC Statement или ResultSet между потоками. Модель программирования JDBC не поддерживает многопоточный доступ, поэтому, вероятно, вы сталкиваетесь с этой ошибкой. А также почему он отлично работает внутри открытого метода, который работает в одном потоке. При использовании JDBC можно кэшировать DataSource, но не Connection или что-то еще ниже Connection. Позвольте серверу приложений управлять объединением подключений и операторов, что он делает потокобезопасным способом.

person njr    schedule 15.02.2017
comment
Идея состоит в том, чтобы эффективно прокручивать набор результатов с помощью одного запроса вместо того, чтобы настраивать Connection, Statement и ResultSet при каждом вызове readItem. Я также использовал эту статью в качестве руководства: radcortez.com/ - person Colby Montgomery; 15.02.2017
comment
Я упустил из виду, что использовался пакет, поэтому операции фактически выполняются в одном и том же потоке, но совет по-прежнему применим, если оракул не позволяет держать курсор открытым при фиксации транзакции xa. - person njr; 16.02.2017
comment
Случайно нажал энтер чтобы скоро. Вот остальная часть комментария. Найденная вами статья, вероятно, написана для однофазного источника данных, который с точки зрения драйвера JDBC будет фиксацией connection.commit, а не фиксацией xa, что может позволить вам продолжать использовать курсор. Я также должен указать, что при использовании этого подхода очень важно убедиться, что ваше соединение закрыто в методе close, чтобы оно не просочилось. - person njr; 16.02.2017