【发布时间】:2017-05-08 14:49:57
【问题描述】:
我在使用 RepositoryItemReader、自定义处理器和 RepositoryItemWriter 将所有更改保存回数据库中的 spring 批处理配置时遇到了问题。我用谷歌搜索了我的手,并不能真正找到答案或看到问题出在哪里:(
我的工作定义是:
@NonNull
@Autowired
private MailRepository repository; //data jpa with hibernate and mssql
@Bean
Job sendMailJob(JobExecutionListener jobCompletionListener) {
return getJobBuilderFactory().get("sendMailJob")
.incrementer(new TimeStampIncrementer())
.listener(jobCompletionListener)
.flow(sendMailStep1())
.end()
.build();
}
@Bean
Step sendMailStep1() {
return getStepBuilderFactory()
.get("sendMailStep1").allowStartIfComplete(true)
.<Mail, Mail> chunk(MAIL_MAX_COUNT)
.reader(mailReader())
.processor(sendMailProcessor())
.writer(mailWriter())
.build();
}
@Bean
ItemReader<Mail> mailReader() {
RepositoryItemReader<Mail> reader = new RepositoryItemReader<>();
reader.setRepository(getRepository());
reader.setPageSize(MAIL_MAX_COUNT);
reader.setMaxItemCount(MAIL_MAX_COUNT);
reader.setMethodName(MailRepository.SEND_BATCH_METHOD_NAME);
reader.setArguments(Arrays.asList(MailStatus.OPEN));
Map<String, Direction> sorting = new HashMap<>();
sorting.put("created", Direction.DESC);
reader.setSort(sorting);
return reader;
}
@Bean
ItemProcessor<Mail ,Mail> sendMailProcessor() {
return new ItemProcessor<Mail, Mail>() {
@Override
public Mail process(Mail mail) throws Exception {
try {
sendMail(mail);
mail.setSent();
} catch (Exception e) {
mail.setFailed();
}
return mail;
}
};
}
@Bean
ItemWriter<Mail> mailWriter() {
RepositoryItemWriter<Mail> writer = new RepositoryItemWriter<>();
writer.setRepository(getRepository());
writer.setMethodName("save");
return writer;
}
这段代码并没有什么特别之处:状态为“OPEN”的邮件将被读取,并由处理器发送,这也会更改状态,并且这些更改应由作者使用 save 写回存储库。
当我调试时,读取、发送和更改状态(不在数据库中)工作正常,但是在编写器调用保存后,所有这些更改都不会保留在数据库中。使用的 PlatformTransactionManager 似乎很好,指向正确的 DataSource 并使用正确的 TransactionMode。在批处理存储库(相同的数据库)内部进行的所有更改都将正确写入,但我在邮件实体中没有任何更改。 我在其他仅读取和删除过期实体的批次中也遇到了这些问题。阅读工作正常,但没有实体被删除。因此,似乎该事务被未提交的存储库使用。也不例外; @EnableBatchProcessing 在应用程序类中设置。
有没有人遇到过同样的问题或者可以帮帮我?
感谢您的建议! 丹尼斯
调试输出:
o.s.batch.repeat.support.RepeatTemplate : Repeat operation about to start at count=1
o.s.b.item.data.RepositoryItemReader : Reading page 0
o.s.orm.jpa.EntityManagerFactoryUtils : Opening JPA EntityManager
o.s.orm.jpa.EntityManagerFactoryUtils : Registering transaction synchronization for JPA EntityManager
o.h.jpa.criteria.CriteriaQueryImpl : Rendered criteria query -> select count(generatedAlias0) from Mail as generatedAlias0 where generatedAlias0.status=:param0
org.hibernate.SQL : select count(mail0_.id) as col_0_0_ from mail mail0_ where mail0_.status=?
Hibernate: select count(mail0_.id) as col_0_0_ from mail mail0_ where mail0_.status=?
org.hibernate.loader.Loader : Result set row: 0
org.hibernate.loader.Loader : Result row:
o.h.jpa.criteria.CriteriaQueryImpl : Rendered criteria query -> select generatedAlias0 from Mail as generatedAlias0 where generatedAlias0.status=:param0 order by generatedAlias0.created desc
org.hibernate.SQL : select TOP(?) mail0_.id as id1_13_, mail0_.created as created2_13_, mail0_.last_modified as last_mod3_13_, mail0_.charset as charset4_13_, mail0_.sender as sender5_13_, mail0_.message as message6_13_, mail0_.sent as sent7_13_, mail0_.status as status8_13_, mail0_.subject as subject9_13_, mail0_.subtype as subtype10_13_, mail0_.suppress_failure as suppres11_13_ from mail mail0_ where mail0_.status=? order by mail0_.created desc
Hibernate: select TOP(?) mail0_.id as id1_13_, mail0_.created as created2_13_, mail0_.last_modified as last_mod3_13_, mail0_.charset as charset4_13_, mail0_.sender as sender5_13_, mail0_.message as message6_13_, mail0_.sent as sent7_13_, mail0_.status as status8_13_, mail0_.subject as subject9_13_, mail0_.subtype as subtype10_13_, mail0_.suppress_failure as suppres11_13_ from mail mail0_ where mail0_.status=? order by mail0_.created desc
org.hibernate.loader.Loader : Result set row: 0
org.hibernate.loader.Loader : Result row: EntityKey[com.some.package.mail.Mail#11]
o.h.engine.internal.TwoPhaseLoad : Resolving associations for [com.some.package.mail.Mail#11]
o.h.engine.internal.TwoPhaseLoad : Done materializing entity [com.some.package.mail.Mail#11]
o.s.batch.repeat.support.RepeatTemplate : Repeat is complete according to policy and result value.
stractLoadPlanBasedCollectionInitializer : Loading collection: [com.some.package.mail.Mail.to#11]
org.hibernate.SQL : select to0_.mail_id as mail_id1_16_0_, to0_.mail_to as mail_to2_16_0_ from mail_to to0_ where to0_.mail_id=?
Hibernate: select to0_.mail_id as mail_id1_16_0_, to0_.mail_to as mail_to2_16_0_ from mail_to to0_ where to0_.mail_id=?
o.h.l.p.e.p.i.ResultSetProcessorImpl : Preparing collection intializer : [com.some.package.mail.Mail.to#11]
o.h.e.l.internal.CollectionLoadContext : 1 collections were found in result set for role: com.some.package.mail.Mail.to
o.h.e.l.internal.CollectionLoadContext : Collection fully initialized: [com.some.package.mail.Mail.to#11]
o.h.e.l.internal.CollectionLoadContext : 1 collections initialized for role: com.some.package.mail.Mail.to
o.h.r.j.i.ResourceRegistryStandardImpl : HHH000387: ResultSet's statement was not registered
stractLoadPlanBasedCollectionInitializer : Done loading collection
stractLoadPlanBasedCollectionInitializer : Loading collection: [com.some.package.mail.Mail.cc#11]
org.hibernate.SQL : select cc0_.mail_id as mail_id1_15_0_, cc0_.cc as cc2_15_0_ from mail_cc cc0_ where cc0_.mail_id=?
Hibernate: select cc0_.mail_id as mail_id1_15_0_, cc0_.cc as cc2_15_0_ from mail_cc cc0_ where cc0_.mail_id=?
o.h.l.p.e.p.i.ResultSetProcessorImpl : Preparing collection intializer : [com.some.package.mail.Mail.cc#11]
o.h.e.l.internal.CollectionLoadContext : 1 collections were found in result set for role: com.some.package.mail.Mail.cc
o.h.e.l.internal.CollectionLoadContext : Collection fully initialized: [com.some.package.mail.Mail.cc#11]
o.h.e.l.internal.CollectionLoadContext : 1 collections initialized for role: com.some.package.mail.Mail.cc
o.h.r.j.i.ResourceRegistryStandardImpl : HHH000387: ResultSet's statement was not registered
stractLoadPlanBasedCollectionInitializer : Done loading collection
stractLoadPlanBasedCollectionInitializer : Loading collection: [com.some.package.mail.Mail.bcc#11]
org.hibernate.SQL : select bcc0_.mail_id as mail_id1_14_0_, bcc0_.bcc as bcc2_14_0_ from mail_bcc bcc0_ where bcc0_.mail_id=?
Hibernate: select bcc0_.mail_id as mail_id1_14_0_, bcc0_.bcc as bcc2_14_0_ from mail_bcc bcc0_ where bcc0_.mail_id=?
o.h.l.p.e.p.i.ResultSetProcessorImpl : Preparing collection intializer : [com.some.package.mail.Mail.bcc#11]
o.h.l.p.e.p.i.ResultSetProcessorImpl : Starting ResultSet row #0
e.p.i.CollectionReferenceInitializerImpl : Found row of collection: [com.some.package.mail.Mail.bcc#11]
o.h.e.l.internal.CollectionLoadContext : 1 collections were found in result set for role: com.some.package.mail.Mail.bcc
o.h.e.l.internal.CollectionLoadContext : Collection fully initialized: [com.some.package.mail.Mail.bcc#11]
o.h.e.l.internal.CollectionLoadContext : 1 collections initialized for role: com.some.package.mail.Mail.bcc
o.h.r.j.i.ResourceRegistryStandardImpl : HHH000387: ResultSet's statement was not registered
stractLoadPlanBasedCollectionInitializer : Done loading collection
o.s.b.item.data.RepositoryItemWriter : Writing to the repository with 1 items.
o.s.j.d.DataSourceTransactionManager : Participating in existing transaction
o.s.b.c.step.item.ChunkOrientedTasklet : Inputs not busy, ended: false
o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=1, written=1, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING]
o.s.j.d.DataSourceTransactionManager : Participating in existing transaction
o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update
o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [UPDATE BATCH_STEP_EXECUTION_CONTEXT SET SHORT_CONTEXT = ?, SERIALIZED_CONTEXT = ? WHERE STEP_EXECUTION_ID = ?]
o.s.jdbc.core.JdbcTemplate : SQL update affected 1 rows
o.s.batch.core.step.tasklet.TaskletStep : Saving step execution before commit: StepExecution: id=158, version=1, name=sendMailStep1, status=STARTED, exitStatus=EXECUTING, readCount=1, filterCount=0, writeCount=1 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0, exitDescription=
o.s.j.d.DataSourceTransactionManager : Participating in existing transaction
o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update
o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [UPDATE BATCH_STEP_EXECUTION set START_TIME = ?, END_TIME = ?, STATUS = ?, COMMIT_COUNT = ?, READ_COUNT = ?, FILTER_COUNT = ?, WRITE_COUNT = ?, EXIT_CODE = ?, EXIT_MESSAGE = ?, VERSION = ?, READ_SKIP_COUNT = ?, PROCESS_SKIP_COUNT = ?, WRITE_SKIP_COUNT = ?, ROLLBACK_COUNT = ?, LAST_UPDATED = ? where STEP_EXECUTION_ID = ? and VERSION = ?]
o.s.jdbc.core.JdbcTemplate : SQL update affected 1 rows
o.s.jdbc.core.JdbcTemplate : Executing prepared SQL query
o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [SELECT VERSION FROM BATCH_JOB_EXECUTION WHERE JOB_EXECUTION_ID=?]
o.s.orm.jpa.EntityManagerFactoryUtils : Closing JPA EntityManager
o.s.j.d.DataSourceTransactionManager : Initiating transaction commit
o.s.j.d.DataSourceTransactionManager : Committing JDBC transaction on Connection [ProxyConnection[PooledConnection[ConnectionID:10 ClientConnectionId: fe7a8cc9-6dcd-4e4c-95d4-ac426b633feb]]]
o.s.j.d.DataSourceTransactionManager : Releasing JDBC Connection [ProxyConnection[PooledConnection[ConnectionID:10 ClientConnectionId: fe7a8cc9-6dcd-4e4c-95d4-ac426b633feb]]] after transaction
o.s.jdbc.datasource.DataSourceUtils : Returning JDBC Connection to DataSource
enter code here
【问题讨论】:
-
您确定您使用的是同一个数据源实例,而不是具有相同配置的第二个实例。从您所写的内容来看,似乎存储库数据源不是事务的一部分,这只有在与将 j 写入批处理存储库的数据源不同时才有可能。
-
感谢您的回复!好点,我只查看了 ds 参数...。我刚刚检查了一下,SimpleJobRepository (-> JdbCStepExecutionDao -> jdbcTemplate) 和 MailRepository (DataSourceConnectionPool) 都指向具有相同实例 id 的同一个 DataSource ..
标签: spring-batch