“Unable to locate persister”错误与Spring Batch + Hibernate ORM相关。

huangapple go评论71阅读模式
英文:

"Unable to locate persister" Error with Spring batch + Hibernate ORM

问题

I'm trying to create a system with Spring batch using Hibernate ORM but can't solve this Error

at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:652) ~[spring-beans-6.0.2.jar:6.0.2]
...

These are my setting files.

Pom.xml

<?xml version="1.0" encoding="UTF-8"?>
...

hibernate-annotation.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"https://hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
...

PersonTest1.java

package com.example.batchprocessing.model;
...

HibernateUtil.java

package com.example.batchprocessing.util;
...

BatchConfiguration.java

package com.example.batchprocessing;
...

This is how my project looks like

英文:

I'm trying to create a system with Spring batch using Hibernate ORM but can't solve this Error

org.springframework.beans.factory.BeanCreationException: Error creating bean with name &#39;reader&#39; defined in class path resource [com/example/batchprocessing/BatchConfiguration.class]: Failed to instantiate [org.springframework.batch.item.file.FlatFileItemReader]: Factory method &#39;reader&#39; threw exception with message: Unable to locate persister: com.example.batchprocessing.model.PersonTest1
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:652) ~[spring-beans-6.0.2.jar:6.0.2]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:488) ~[spring-beans-6.0.2.jar:6.0.2]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1324) ~[spring-beans-6.0.2.jar:6.0.2]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1161) ~[spring-beans-6.0.2.jar:6.0.2]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561) ~[spring-beans-6.0.2.jar:6.0.2]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[spring-beans-6.0.2.jar:6.0.2]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[spring-beans-6.0.2.jar:6.0.2]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.0.2.jar:6.0.2]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[spring-beans-6.0.2.jar:6.0.2]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.0.2.jar:6.0.2]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:961) ~[spring-beans-6.0.2.jar:6.0.2]
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:915) ~[spring-context-6.0.2.jar:6.0.2]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584) ~[spring-context-6.0.2.jar:6.0.2]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730) ~[spring-boot-3.0.0.jar:3.0.0]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432) ~[spring-boot-3.0.0.jar:3.0.0]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[spring-boot-3.0.0.jar:3.0.0]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302) ~[spring-boot-3.0.0.jar:3.0.0]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291) ~[spring-boot-3.0.0.jar:3.0.0]
	at com.example.batchprocessing.BatchProcessingApplication.main(BatchProcessingApplication.java:12) ~[classes/:na]

This is how my project looks like

These are my setting files.

Pom.xml

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
	xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
	&lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
	&lt;parent&gt;
		&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
		&lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;
		&lt;version&gt;3.0.0&lt;/version&gt;
		&lt;relativePath/&gt; &lt;!-- lookup parent from repository --&gt;
	&lt;/parent&gt;
	&lt;groupId&gt;com.example&lt;/groupId&gt;
	&lt;artifactId&gt;batch-processing-complete&lt;/artifactId&gt;
	&lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;
	&lt;name&gt;batch-processing-complete&lt;/name&gt;
	&lt;description&gt;Demo project for Spring Boot&lt;/description&gt;
	&lt;properties&gt;
		&lt;java.version&gt;17&lt;/java.version&gt;
	&lt;/properties&gt;
	&lt;dependencies&gt;
		&lt;dependency&gt;
			&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
			&lt;artifactId&gt;spring-boot-starter-batch&lt;/artifactId&gt;
		&lt;/dependency&gt;

		&lt;dependency&gt;
			&lt;groupId&gt;org.hsqldb&lt;/groupId&gt;
			&lt;artifactId&gt;hsqldb&lt;/artifactId&gt;
			&lt;scope&gt;runtime&lt;/scope&gt;
		&lt;/dependency&gt;
		&lt;dependency&gt;
			&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
			&lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
			&lt;scope&gt;test&lt;/scope&gt;
		&lt;/dependency&gt;
		&lt;dependency&gt;
			&lt;groupId&gt;org.springframework.batch&lt;/groupId&gt;
			&lt;artifactId&gt;spring-batch-test&lt;/artifactId&gt;
			&lt;scope&gt;test&lt;/scope&gt;
		&lt;/dependency&gt;
		
		&lt;dependency&gt;
			&lt;groupId&gt;org.hibernate&lt;/groupId&gt;
			&lt;artifactId&gt;hibernate-core&lt;/artifactId&gt;
			&lt;version&gt;6.2.0.Final&lt;/version&gt;
		&lt;/dependency&gt;
		&lt;dependency&gt;
			&lt;groupId&gt;org.postgresql&lt;/groupId&gt;
			&lt;artifactId&gt;postgresql&lt;/artifactId&gt;
		&lt;/dependency&gt;
	&lt;/dependencies&gt;

	&lt;build&gt;
		&lt;plugins&gt;
			&lt;plugin&gt;
				&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
				&lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
			&lt;/plugin&gt;
		&lt;/plugins&gt;
	&lt;/build&gt;

&lt;/project&gt;

hibernate-annotation.cfg.xml

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE hibernate-configuration PUBLIC
		&quot;-//Hibernate/Hibernate Configuration DTD 3.0//EN&quot;
		&quot;https://hibernate.org/dtd/hibernate-configuration-3.0.dtd&quot;&gt;

&lt;hibernate-configuration&gt;
	&lt;session-factory&gt;
		&lt;!-- Database connection properties - Driver, URL, user, password --&gt;
		&lt;property name=&quot;hibernate.connection.driver_class&quot;&gt;org.postgresql.Driver&lt;/property&gt;
		&lt;property name=&quot;hibernate.connection.url&quot;&gt;jdbc:postgresql://localhost:5432/testdb&lt;/property&gt;
		&lt;property name=&quot;hibernate.connection.username&quot;&gt;postgres&lt;/property&gt;
		&lt;property name=&quot;hibernate.connection.password&quot;&gt;password&lt;/property&gt;
		
		&lt;!-- org.hibernate.HibernateException: No CurrentSessionContext configured! --&gt;
		&lt;property name=&quot;hibernate.current_session_context_class&quot;&gt;thread&lt;/property&gt;
		
		&lt;!-- Mapping with model class containing annotations --&gt;
		&lt;mapping class=&quot;com.example.batchprocessing.model.PersonTest1&quot; /&gt;
	&lt;/session-factory&gt;
&lt;/hibernate-configuration&gt;

PersonTest1.java
Notthing special here.

package com.example.batchprocessing.model;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name=&quot;people&quot;)
public class PersonTest1 {
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Column(name=&quot;person_id&quot;, nullable=false, unique=true, length=11)
	private int personId;
	
	@Column(name=&quot;last_name&quot;)
	private String lastName;
	
	@Column(name=&quot;first_name&quot;)
	private String firstName;

	public int getPersonId() {
		return personId;
	}

	public void setPersonId(int personId) {
		this.personId = personId;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
}

HibernateUtil.java
I just copied this from internet so hope there is no problem here.

package com.example.batchprocessing.util;

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.example.batchprocessing.JobCompletionNotificationListener;

public class HibernateUtil {
	private static final Logger log = LoggerFactory.getLogger(JobCompletionNotificationListener.class);
	
	//Annotation based configuration
	private static SessionFactory sessionAnnotationFactory;
	
	private static SessionFactory buildSessionAnnotationFactory() {
		try {
			Configuration configuration = new Configuration();
			configuration.configure(&quot;hibernate-annotation.cfg.xml&quot;);
			log.info(&quot;--- Hibernate Configuration loaded ---&quot;);
			
			ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
			log.info(&quot;--- Hibernate Annotation serviceRegistry created ---&quot;);
			
			SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
			
			return sessionFactory;
			
		} catch (Throwable ex) {
			log.error(&quot;--- Initial SessionFactory creation failed.&quot; + ex);
			throw new ExceptionInInitializerError(ex);
		}
	}
	
	public static SessionFactory getSessionAnnotationFactory() {
		sessionAnnotationFactory = buildSessionAnnotationFactory();
		
		return sessionAnnotationFactory;
	}
}

BatchConfiguration.java
reader() is where I am trying to write to DB.

package com.example.batchprocessing;

import javax.sql.DataSource;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.transaction.PlatformTransactionManager;

import com.example.batchprocessing.model.PersonTest1;
import com.example.batchprocessing.util.HibernateUtil;

@Configuration
public class BatchConfiguration {
	
	private static final Logger log = LoggerFactory.getLogger(JobCompletionNotificationListener.class);

	// tag::readerwriterprocessor[]
	@Bean
	public FlatFileItemReader&lt;Person&gt; reader() {
		
		PersonTest1 personTest = new PersonTest1();
		personTest.setLastName(&quot;John&quot;);
		personTest.setFirstName(&quot;Wick&quot;);
		
		// Get Session
		log.info(&quot;--- Creating session ---&quot;);
		SessionFactory sessionFactory = HibernateUtil.getSessionAnnotationFactory();
		Session session = sessionFactory.getCurrentSession();
		
		log.info(&quot;--- Starting transaction ---&quot;);
		session.beginTransaction();
		
		log.info(&quot;--- Saving model ---&quot;);
		session.persist(personTest);
		
		log.info(&quot;--- Commiting transaction ---&quot;);
		session.getTransaction().commit();
		
		log.info(&quot;--- Closing session ---&quot;);
		sessionFactory.close();
		
		return new FlatFileItemReaderBuilder&lt;Person&gt;()
			.name(&quot;personItemReader&quot;)
			.resource(new ClassPathResource(&quot;sample-data.csv&quot;))
			.delimited()
			.names(new String[]{&quot;firstName&quot;, &quot;lastName&quot;})
			.fieldSetMapper(new BeanWrapperFieldSetMapper&lt;Person&gt;() {{
				setTargetType(Person.class);
			}})
			.build();
	}

	@Bean
	public PersonItemProcessor processor() {
		return new PersonItemProcessor();
	}

	@Bean
	public JdbcBatchItemWriter&lt;Person&gt; writer(DataSource dataSource) {
		return new JdbcBatchItemWriterBuilder&lt;Person&gt;()
			.itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider&lt;&gt;())
			.sql(&quot;INSERT INTO people (first_name, last_name) VALUES (:firstName, :lastName)&quot;)
			.dataSource(dataSource)
			.build();
	}
	// end::readerwriterprocessor[]

	// tag::jobstep[]
	@Bean
	public Job importUserJob(JobRepository jobRepository,
			JobCompletionNotificationListener listener, Step step1) {
		return new JobBuilder(&quot;importUserJob&quot;, jobRepository)
			.incrementer(new RunIdIncrementer())
			.listener(listener)
			.flow(step1)
			.end()
			.build();
	}

	@Bean
	public Step step1(JobRepository jobRepository,
			PlatformTransactionManager transactionManager, JdbcBatchItemWriter&lt;Person&gt; writer) {
		return new StepBuilder(&quot;step1&quot;, jobRepository)
			.&lt;Person, Person&gt; chunk(10, transactionManager)
			.reader(reader())
			.processor(processor())
			.writer(writer)
			.build();
	}
	// end::jobstep[]
}

答案1

得分: 1

This line in HibernateUtil is problematic because applySettings will only apply properties but no mappings:

HibernateUtil中的这行代码存在问题因为`applySettings`只会应用属性而不会应用映射
```java

Judging from the implementation of Configuration.configure(String resource), you need to call StandardServiceRegistryBuilder.configure(String resource) to apply the mappings declared in hibernate-annotation.cfg.xml:

根据Configuration.configure(String resource)的实现,你需要调用StandardServiceRegistryBuilder.configure(String resource)来应用在hibernate-annotation.cfg.xml中声明的映射:

Or, if you don't actually have a reason to create the ServiceRegistry yourself, instead call configuration.buildSessionFactory() and let the Configuration class use the internal StandardServiceRegistryBuilder.

或者,如果你实际上没有理由自己创建ServiceRegistry,可以调用configuration.buildSessionFactory(),让Configuration类使用内部的StandardServiceRegistryBuilder。

英文:

This line in HibernateUtil is problematic because applySettings will only apply properties but no mappings:

ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
        .applySettings(configuration.getProperties())
        .build();

Judging from the implementation of Configuration.configure(String resource), you need to call StandardServiceRegistryBuilder.configure(String resource) to apply the mappings declared in hibernate-annotation.cfg.xml:

ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
        .configure(&quot;hibernate-annotation.cfg.xml&quot;)
        .build();

Or, if you don't actually have a reason to create the ServiceRegistry yourself, instead call configuration.buildSessionFactory() and let the Configuration class use the internal StandardServiceRegistryBuilder.

huangapple
  • 本文由 发表于 2023年4月13日 19:11:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/76004746.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定