Spring batch не запускает транзакцию при использовании специального средства записи - PullRequest
0 голосов
/ 17 октября 2019

Я работаю над подпружиненным пакетом, который читает из файла CSV и записывает в базу данных. Я использую FlatFileItemReader для чтения файла и реализовал ItemWriter, который использует Jpa для вставки данных в базу данных. Но пакетный сбой без выполнения транзакции. Вот моя конфигурация работы

<bean id="datasource" class="oracle.jdbc.pool.OracleDataSource">
    <property name="user" value="xxx" />
    <property name="password" value="xx" />
    <property name="URL" value="xxx" />
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<bean id="entityManagerFactory" name="model"
      class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="datasource"/>

    <property name="jpaVendorAdapter">
        <bean
                class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="generateDdl" value="false"/>
            <property name="showSql" value="true"/>
            <property name="database">
                <util:constant
                        static-field="org.springframework.orm.jpa.vendor.Database.ORACLE"/>
            </property>
            <property name="databasePlatform" value="org.hibernate.dialect.Oracle12cDialect"/>
        </bean>
    </property>
</bean>

<batch:job id="testJob">
    <batch:step id="step">
        <batch:tasklet>
            <batch:chunk reader="cvsFileItemReader" writer="databaseWriter"
                         commit-interval="10">
            </batch:chunk>
        </batch:tasklet>
    </batch:step>
</batch:job>

А ниже мой писатель

public class DatabaseWriter implements ItemWriter<Report> {


private EntityManagerFactory entityManagerFactory;

@Autowired
public DatabaseWriter(EntityManagerFactory entityManagerFactory) {
    this.entityManagerFactory = entityManagerFactory;
}

@Override
public void write(List<? extends Report> list) throws Exception {
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    for (Report report : list) {


        entityManager.persist(report );
    }
    entityManager.flush();

}

}

Это работает, только если явно начать транзакцию. Это как ниже

public class DatabaseWriter implements ItemWriter<Report> {


private EntityManagerFactory entityManagerFactory;

@Autowired
public DatabaseWriter(EntityManagerFactory entityManagerFactory) {
    this.entityManagerFactory = entityManagerFactory;
}

@Override
public void write(List<? extends Report> list) throws Exception {
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    entityManager.getTransaction().begin();
    for (Report report : list) {

        entityManager.persist(report );
    }
    entityManager.getTransaction().commit();

}

}

Действительно ли необходимо, чтобы транзакция поддерживалась явно, а Spring Batch не контролировал ее из коробки?

EDIT

Я исправил это, изменив писателя, например

public class DatabaseWriter implements ItemWriter<Report> {


@PersistenceContext
private EntityManager entityManager;

@Override

public void write(List<? extends Report> list)  {
    for (Report report : list) {
        entityManager.persist(report );
    }


}

Изменение EntityMangerFactory на EntityManager с PersistenceContext устранило проблему. Но я изо всех сил пытаюсь понять причину этого поведения

Ответы [ 2 ]

1 голос
/ 18 октября 2019

Но я изо всех сил пытаюсь понять причину такого поведения

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

Следует иметь в виду, что тасклет выполняется в транзакции, управляемой Spring Batch (включая средство записи элементов для тасклета, ориентированного на чанк). Поэтому любой код, работающий в этой области, должен соответствовать определению транзакции тасклета. В вашем случае EntityManager, введенный в записывающее устройство, управляется указанным вами JpaTransactionManager, который также используется Spring Batch для транзакции тасклета.

В качестве примечания можно использовать JpaItemWriter предоставляется Spring Batch вместо написания пользовательского писателя. Код практически идентичен.

0 голосов
/ 18 октября 2019

Создайте DAO, переместите туда свой код JPA и автоматически подключите DAO к своему устройству записи.

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

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