Информация перед фронтом. Я только что выбрал фрагменты кода, которые, по моему мнению, необходимы, они находятся в разных файлах, поэтому не удивляйтесь, выглядит ли это немного запутанным.Весенняя партия + спящий режим записи во время выбора
Я читаю из плоского файла во время моего чтения 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
Не могли бы вы показать мне метод выборки(), а также Писатель? –
В основном метод выборки использует Дао для поиска продукта по id и другим другим критериям. например productDao.getById (критерии [0]). Если он остается пустым, то в конце он вызовет create() с фабрики, который по сути просто возвращает новый Product(). Полный метод проверяет некоторые ограничения, а затем некоторые findBy зависят от разных критериев, но довольно длинный, поэтому i не хотел публиковать его. Писатель можно найти в конце последнего ввода кода. Это только JpaItemWriter по умолчанию. – Xtroce
Хорошо, не могли бы вы прояснить «элемент, который изменяется во время партии. Я получаю проблему, из-за которой hibernate выполняет инструкцию обновления во время выбора следующего элемента». ? Я понимаю, но я не симпатичный. Пожалуйста, проясните точно проблему (трассировка стека и исключение, если требуется) –