2016-09-02 3 views
3

Информация перед фронтом. Я только что выбрал фрагменты кода, которые, по моему мнению, необходимы, они находятся в разных файлах, поэтому не удивляйтесь, выглядит ли это немного запутанным.Весенняя партия + спящий режим записи во время выбора

Я читаю из плоского файла во время моего чтения SpringBatch. Я написал ProductValueMapper, вызванный из FieldSetMapper, который сопоставляет столбцы с моделью Hibernate. Этот сопоставитель также проверяет, существует ли продукт в базе данных, и если да, использует Entity из базы данных, иначе он создаст новый.

@Component 
@StepScope 
public class ProductValueMapper { 

    @Autowired 
    private IProductDao productDao; 

    @Autowired 
    private IFactory<Product> productFactory; 

    private Product fetch(String[] criteria) { 
     //... try to fetch product using different criteria, or create a new one using the factory ... 
     return product; 
    } 

    Product map(String[] criteria) { 
      Product product = fetch(criteria); 
      //... map some stuff ...  
      return product; 
    } 

}

дао нам получить менеджер объект Autowired по

@PersistenceContext 
private EntityManager manager; 

и помечены как @Transactional

После этого у меня есть процессор, который делает nothingexcept лесозаготовок.

Тогда я пишу jpaItemWriter по умолчанию с создается следующим образом:

@Configuration 
@Import(DatabaseConfiguration.class) 
public class HibernateConfiguration extends DefaultBatchConfigurer { 

    @Autowired 
    @Qualifier("oracleDataSource") 
    private DataSource dataSource; 

    @Bean(name = "jpaEntitiyManager") 
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() { 
     LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); 
     em.setPersistenceUnitName("hibernatePersistenceUnit"); 
     em.setPackagesToScan("com.somepackage"); 
     em.setDataSource(dataSource); 
     em.setJpaProperties(hibernateProperties()); 

     HibernateJpaVendorAdapter vendor = new HibernateJpaVendorAdapter(); 
     vendor.setGenerateDdl(false); 
     vendor.setShowSql(true); 
     em.setJpaVendorAdapter(vendor); 
     return em; 
    } 

    @Bean 
    public Properties hibernateProperties() { 
     Properties prop = new Properties(); 
     prop.setProperty("hibernate.hbm2ddl.auto", "validate"); 
     prop.setProperty("hibernate.dialect", "org.hibernate.dialect.Oracle10gDialect"); 
     prop.setProperty("hibernate.globally_quoted_identifiers", "false"); 
     prop.setProperty("hibernate.show_sql", "true"); 
     return prop; 
    } 

    @Override 
    public PlatformTransactionManager getTransactionManager() { 
     final JpaTransactionManager transactionManager = new JpaTransactionManager(); 
     transactionManager.setEntityManagerFactory(entityManagerFactory().getObject()); 
    return transactionManager; 
    } 
} 

@Configuration 
@EnableBatchProcessing(modular = true) 
@ComponentScan({"com.somepackage"}) 
@Import({HibernateConfiguration.class, DatabaseConfiguration.class}) 
public class BatchConfiguration { 

    @Autowired 
    public EntityManagerFactory emf; 

    @Bean 
    public JpaItemWriter<ProductEntity> jpaItemWriter() { 
     JpaItemWriter<ProductEntity> itemWriter = new JpaItemWriter<>(); 
     itemWriter.setEntityManagerFactory(emf); 
     return itemWriter; 
    } 

    //... rest of the setup for the job 

} 

Программа работает как ожидается, кроме того, что с chunksize> 1 и элемент, который получает изменен во время партии я получаю эту проблему что hibernate выполняет оператор обновления во время выбора следующего элемента.

Я знаю, что я могу решить это, либо вызвав флеш, либо сохранив в процессоре, либо уменьшив размер блока до 1, но почему-то оба решения чувствуют себя не так. Должна ли существовать транзакция за каждый элемент, открытый, а затем при вызове писателя эти транзакции должны выполняться один за другим? Или я не понимаю принцип транзакцииHandling весной Batch.

* EDIT 1 *

проблема заключается в том, что при установке размер порции 1 программа ведет себя, как и ожидалось: обновление происходит во время фазы записи.

2016-09-05 11:20:40.828 INFO 11084 --- [   main] n.e.p.i.logging.LogItemReadListener  : ItemReadListener - beforeRead 
2016-09-05 11:20:40.828 INFO 11084 --- [   main] n.e.p.i.r.map.GenericProductMapper : Processing product: Prduct1 
Hibernate: select productent0_.PRODUCTSN as PRODUCTSN1_25_, ..... 
2016-09-05 11:20:40.832 INFO 11084 --- [   main] n.e.p.i.logging.LogItemReadListener  : ItemReadListener - afterRead: [email protected] 
2016-09-05 11:20:40.832 INFO 11084 --- [   main] n.e.p.i.logging.LogItemWriterListener : ItemWriteListener - beforeWrite 
Hibernate: update PIME.PRODUCT set AVAILABILITYDATE=?, .... 
2016-09-05 11:20:40.836 INFO 11084 --- [   main] n.e.p.i.logging.LogItemWriterListener : ItemWriteListener - afterWrite 
2016-09-05 11:20:40.887 INFO 11084 --- [   main] n.e.p.i.logging.LogItemReadListener  : ItemReadListener - beforeRead 
2016-09-05 11:20:40.887 INFO 11084 --- [   main] n.e.p.i.r.map.GenericProductMapper : Processing product: Product2 
Hibernate: select productent0_.PRODUCTSN as PRODUCTSN1_25_, .... 
2016-09-05 11:20:40.891 INFO 11084 --- [   main] n.e.p.i.logging.LogItemReadListener  : ItemReadListener - afterRead: [email protected] 
2016-09-05 11:20:40.891 INFO 11084 --- [   main] n.e.p.i.logging.LogItemWriterListener : ItemWriteListener - beforeWrite 
2016-09-05 11:20:40.891 INFO 11084 --- [   main] n.e.p.i.logging.LogItemWriterListener : ItemWriteListener - afterWrite 

Но когда размер блока увеличиваются случается запись в fornt избранного заявления, так как запись не происходит в конце обработки продукта, но в кусках:

2016-09-05 11:09:36.240 INFO 12408 --- [   main] n.e.p.i.logging.LogItemReadListener  : ItemReadListener - beforeRead 
2016-09-05 11:09:36.240 INFO 12408 --- [   main] n.e.p.i.r.map.GenericProductMapper : Processing product: Product1 
Hibernate: select productent0_.PRODUCTSN as PRODUCTSN1_25_, .... 
2016-09-05 11:09:36.244 INFO 12408 --- [   main] n.e.p.i.logging.LogItemReadListener  : ItemReadListener - afterRead: [email protected] 
2016-09-05 11:09:36.244 INFO 12408 --- [   main] n.e.p.i.logging.LogItemReadListener  : ItemReadListener - beforeRead 
2016-09-05 11:09:36.244 INFO 12408 --- [   main] n.e.p.i.r.map.GenericProductMapper : Processing product: Product2 
Hibernate: update PIME.PRODUCT set AVAILABILITYDATE=?, .... 
Hibernate: select productent0_.PRODUCTSN as PRODUCTSN1_25_, .... 
2016-09-05 11:09:36.250 INFO 12408 --- [   main] n.e.p.i.logging.LogItemReadListener  : ItemReadListener - afterRead: [email protected] 
2016-09-05 11:09:36.250 INFO 12408 --- [   main] n.e.p.i.logging.LogItemReadListener  : ItemReadListener - beforeRead 
2016-09-05 11:09:36.250 INFO 12408 --- [   main] n.e.p.i.r.map.GenericProductMapper : Processing product: Product3 
Hibernate: select productent0_.PRODUCTSN as PRODUCTSN1_25_, .... 
2016-09-05 11:09:36.253 INFO 12408 --- [   main] n.e.p.i.logging.LogItemReadListener  : ItemReadListener - afterRead: [email protected] 
2016-09-05 11:09:36.253 INFO 12408 --- [   main] n.e.p.i.logging.LogItemReadListener  : ItemReadListener - beforeRead 
2016-09-05 11:09:36.253 INFO 12408 --- [   main] n.e.p.i.r.map.GenericProductMapper : Processing product: Product4 
Hibernate: select productent0_.PRODUCTSN as PRODUCTSN1_25_, .... 
2016-09-05 11:09:36.256 INFO 12408 --- [   main] n.e.p.i.logging.LogItemReadListener  : ItemReadListener - afterRead: [email protected] 
2016-09-05 11:09:36.256 INFO 12408 --- [   main] n.e.p.i.logging.LogItemWriterListener : ItemWriteListener - beforeWrite 
2016-09-05 11:09:36.257 INFO 12408 --- [   main] n.e.p.i.logging.LogItemWriterListener : ItemWriteListener - afterWrite 
+0

Не могли бы вы показать мне метод выборки(), а также Писатель? –

+0

В основном метод выборки использует Дао для поиска продукта по id и другим другим критериям. например productDao.getById (критерии [0]). Если он остается пустым, то в конце он вызовет create() с фабрики, который по сути просто возвращает новый Product(). Полный метод проверяет некоторые ограничения, а затем некоторые findBy зависят от разных критериев, но довольно длинный, поэтому i не хотел публиковать его. Писатель можно найти в конце последнего ввода кода. Это только JpaItemWriter по умолчанию. – Xtroce

+0

Хорошо, не могли бы вы прояснить «элемент, который изменяется во время партии. Я получаю проблему, из-за которой hibernate выполняет инструкцию обновления во время выбора следующего элемента». ? Я понимаю, но я не симпатичный. Пожалуйста, проясните точно проблему (трассировка стека и исключение, если требуется) –

ответ

2

Мы необходимо использовать Entry вместо Entity. Наилучшей практикой для вас в этом случае является только

  1. Из Reader вы запрашиваете базу данных и сохраняете ее как запись (Pojo) not Entity.
  2. От процессора вы обрабатываете вход
  3. Из Writer вы обновляете базу данных по идентификатору из записи. (Или вы можете использовать Бульдозер для отображения от объекта к Pojo)

В противном случае, весна будет выполнять вещи, как показано ниже:

  1. Reader, вы принести и сохранить его в качестве активного Entity А.
  2. Процессор, вы меняете непосредственно на объект A
  3. Другой читатель, вы забираете B, а затем Spring обновляет A, потому что они отклоняют изменение непосредственно на сущности A.

Примечание: если вы не хотите, чтобы это произошло, вы можете использовать @ReadOnly вместе с @Transactional

Спасибо, Nghia

+0

это, кажется, хорошее решение, но два вопроса для него. Продукт состоит из довольно большого количества данных, связанных с ним. Это делается с помощью LAZY в режиме спящего режима. Может ли это быть проблемой при копировании с бульдозером. Также, если я добавлю аннотацию ReadOnly к аннотации Transactional, не блокирует ли это возможность записи объекта через SpringBatch в конце? – Xtroce

+0

Вы можете попробовать Session.setReadOnly ([объект сущности], true | false) для включения/выключения * readonly * –

Смежные вопросы