所以我正在尝试构建一个使用Hibernate写入MySQL数据库的应用程序,并且有一段时间试图让它工作。简而言之,它没有看到Session,即使我已经配置了一个和Autowired。这就是我的代码明智。
首先是所述应用程序的配置:
@EnableBatchProcessing
@SpringBootApplication(scanBasePackages="com.lcbo")
@EnableIntegration
public class BatchConfig {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public Job processLCBOInventory(@Qualifier("getCurrentLCBODataStep") final Step getCurrentLCBODataStep,
@Qualifier("getLCBOStoreDataStep") final Step getLCBOStoreDataStep,
final JobExecutionListenerConfig jelcListener
) {
return jobBuilderFactory
.get("processLCBOInventory")
.incrementer(new RunIdIncrementer())
.start(getCurrentLCBODataStep)
.next(getLCBOStoreDataStep)
.listener(jelcListener)
.build();
}
@Bean
public Step getLCBOStoreDataStep(final LCBOStoreReader lcboStoreReader,
final LCBOStoreProcessor lcboStoreProcessor,
final LCBOStoreWriter lcboStoreWriter,
final ExecutionContextPromotionListener listener) throws Exception {
return stepBuilderFactory
.get("getLCBOStoreDataStep")
.<LCBOStore, LCBOStore>chunk(inventoryTrackerProperties.getDefaults().getChunkSize())
.reader(lcboStoreReader.read())
.processor(lcboStoreProcessor)
.writer(lcboStoreWriter)
.listener(listener)
.build();
}
然后,作者:
@Component
public class LCBOStoreWriter extends HibernateItemWriter<LCBOStore> {
@Autowired
private LCBOStoreService lcboStoreService;
@Autowired
private DatabaseConfig dbConfigy;
private static final Logger log = LoggerFactory.getLogger(LCBOStoreWriter.class);
@Override
public void write(List<? extends LCBOStore> lcboStoreItems) {
for (LCBOStore lcboStoreItem : lcboStoreItems) {
lcboStoreService.addNewStore(lcboStoreItem);
}
}
和DatabaseConfig文件内容:
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.lcbo.domain")
public class DatabaseConfig {
@Autowired
private LCBOInventoryTrackerProperties properties;
@Bean
public EntityManagerFactory entityManagerFactory() throws SQLException {
final LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean.setJpaDialect(new HibernateJpaDialect());
factoryBean.setJpaProperties(getHibernateProperties());
factoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
factoryBean.setPackagesToScan("com.lcbo.domain");
factoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
factoryBean.setPersistenceUnitName("persistenceUnit");
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
@Bean(destroyMethod = "")
public DataSource dataSource() throws SQLException {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(properties.getDb().getDriver());
dataSource.setUrl(properties.getDb().getUrl());
dataSource.setUsername(properties.getDb().getUsername());
dataSource.setPassword(properties.getDb().getPassword());
return dataSource;
}
甚至尝试过SessionFactory本身,就像这样
public LocalSessionFactoryBean getSessionFactory() throws SQLException {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "com.bytestree.model" });
sessionFactory.setHibernateProperties(getHibernateProperties());
return sessionFactory;
}
但没有骰子。我还尝试将一个SessionFactory实例注入到HibernateItemWriter附带的setSessionFactory中,再次,没有骰子。
我知道我遇到了一些问题,问题是它希望SessionFactory能够被应用程序重新配置,或者我是否将这个编写器配置为接近正确的位置?
编辑:根据要求,运行此代码时显示在intellj中的堆栈跟踪。
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'LCBOInventoryWriter' defined in file [C:\workspace\LCBOInventoryTracker\target\classes\com\lcbo\writer\LCBOInventoryWriter.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Either HibernateOperations or SessionFactory must be provided
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866) ~[spring-context-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542) ~[spring-context-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:737) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:370) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:314) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1162) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1151) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at com.lcbo.config.LCBOBatchConfig.main(LCBOBatchConfig.java:157) [classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_102]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_102]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_102]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_102]
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147) [idea_rt.jar:na]
Caused by: java.lang.IllegalStateException: Either HibernateOperations or SessionFactory must be provided
at org.springframework.util.Assert.state(Assert.java:392) ~[spring-core-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.batch.item.database.HibernateItemWriter.afterPropertiesSet(HibernateItemWriter.java:93) ~[spring-batch-infrastructure-3.0.7.RELEASE.jar:3.0.7.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
... 20 common frames omitted
答案 0 :(得分:1)
由于HibernateItemWriter是第三方依赖项,我认为将LCBOStoreWriter设置为@Bean
而不是@Component
可能更好,并在那里设置sessionFactory
。
从LCBOStoreWriter中移除@Component
并将以下内容添加到BatchConfig
@Bean
public LCBOStoreWriter lCBOStoreWriter() {
LCBOStoreWriter wr = new LCBOStoreWriter();
wr.setSessionFactory(sessionFactory())
return wr;
}
如果没有自动装配,您可能需要设置lcboStoreService和dbConfigy。或者,你可以用其他方式注射它们,我不记得所有的方式......
@Bean
public SessionFactory sessionFactory() throws SQLException {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "com.bytestree.model" });
sessionFactory.setHibernateProperties(getHibernateProperties());
return sessionFactory.getObject();
}
答案 1 :(得分:0)
因此,根据我收到的反馈,听起来就像我担心的那样,我创建了一个frakenstein解决方案,从多个来源在线拼凑而成。通过大量的帮助和一些反复试验,我通过以下方式解决了这个问题。
首先,这是作家现在的样子。
@Component
public class LCBOStoreWriter implements ItemWriter<LCBOStore> {
@Autowired
private DatabaseConfig dbConfig;
@Override
public void write(List<? extends LCBOStore> items) throws Exception {
JpaItemWriter wr = new JpaItemWriter();
wr.setEntityManagerFactory(dbConfig.entityManagerFactory());
wr.write(items);
}
}
编辑:我扩展了作者主要是因为将功能分离到自己的类中。我发现随着项目的进行,这些事情就像扩展一样,所以一开始就把它们分开。另外我喜欢这个样子。话虽如此,它并不是必需的,而且是@M。 Deinum指出可以使事情变得更加复杂。除非你知道你需要使用自定义编写器扩展功能,或者像我一样愚蠢的事情,你发现分离看起来更好代码,请使用@qtips创建的内容,然后在步骤配置中为您添加方法作家。
然后是LCBOStore,它是java对象和Hibernate / JPA注释的组合。
@Entity
@Table(name = "store")
public class LCBOStore {
@Id
@Column(name = "id", unique = true, nullable = false)
private Long id;
@Column(name = "addressLineOne", length = 255)
private String addressLineOne;
@Column(name = "addressLineTwo", length = 255)
private String addressLineTwo;
@Column(name = "city", length = 255)
private String city;
@Column(name = "postalCode", length = 10)
private String postalCode;
@Column(name = "latitude", length = 255)
private String latitude;
@Column(name = "longitude", length = 255)
private String longitude;
@Column(name = "updatedAt", length = 255)
private String updatedAt; //Convert to Date
//getters and setters
}
自动装配的entityManagerFactory类:
@Bean
public EntityManagerFactory entityManagerFactory() throws SQLException {
final LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean.setJpaDialect(new HibernateJpaDialect());
factoryBean.setJpaProperties(getHibernateProperties());
factoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
factoryBean.setPackagesToScan("com.lcbo.batch.domain");
factoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
factoryBean.setPersistenceUnitName("persistenceUnit");
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
以及步骤
的配置@Bean
public Step getLCBOStoreDataStep(final LCBOStoreReader lcboStoreReader,
final LCBOStoreProcessor lcboStoreProcessor,
final LCBOStoreWriter lcboStoreWriter,
final ExecutionContextPromotionListener listener) throws Exception {
return stepBuilderFactory
.get("getLCBOStoreDataStep")
.<LCBOStore, LCBOStore>chunk(inventoryTrackerProperties.getDefaults().getChunkSize())
.reader(lcboStoreReader.read())
.processor(lcboStoreProcessor)
.writer(lcboStoreWriter)
.listener(listener)
.build();
}
我要感谢qtips和M. Deinum对此的帮助。非常感谢!