java - 如何使用 Spring Batch 和 Hibernate 从 @JoinColumn 获取值

标签 java spring hibernate jpa spring-batch

简介

为了从数据库中提取一些数据,我正在尝试设置一个基本的 Hibernate 和 Spring Batch 项目。目标是提供一个查询(HQL),并基于此查询,Spring Batch 应用程序将所有数据提取到一个平面文件中。

应用程序的要求之一是用户不必配置列的映射。因此,我试图创建一个 DynamicRecordProcessor,它评估输入并将输入(例如地址的表)传递给编写器,以便平面文件项编写器可以使用 PassThroughFieldExtractor。

读取器-处理器-写入器 xml 配置下方:

<!-- Standard Spring Hibernate Reader -->
<bean id="hibernateItemReader" class="org.springframework.batch.item.database.HibernateCursorItemReader">
    <property name="sessionFactory" ref="sessionFactory" />         
    <property name="queryString" value="from Address" />                
</bean> 

<!-- Custom Processor -->
<bean id="dynamicRecordProcessor" class="nl.sander.mieras.processor.DynamicRecordProcessor"/>   

<!-- Standard Spring Writer -->
<bean id="itemWriter" class="org.springframework.batch.item.file.FlatFileItemWriter">
    <property name="resource" value="file:target/extract/output.txt" />  
    <property name="lineAggregator">
        <bean class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
            <property name="delimiter" value="|"/>
            <property name="fieldExtractor">
                <bean class="org.springframework.batch.item.file.transform.PassThroughFieldExtractor"/>                                   
            </property>             
        </bean>
    </property>
</bean>

编辑: 以及作业配置:

<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
    <property name="jobRepository" ref="jobRepository" />
</bean>

<bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
    <property name="transactionManager" ref="transactionManager"/>
</bean> 

<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    <property name="configLocation" value="classpath:hibernate.cfg.xml"/>           
    <property name="cacheableMappingLocations" value="classpath*:META-INF/mappings/*.hbm.xml"/>    
</bean> 

<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager" lazy-init="true">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

问题

我的处理器如下所示:

public class DynamicRecordProcessor<Input,Output> implements ItemProcessor<Input,Output> {  

    private static final String DELIMITER = "|";
    private boolean areNamesSetup = false;

    private List<String> names = new ArrayList<String>();
    private Input item;

    @SuppressWarnings("unchecked")
    @Override
    public Output process(Input item) throws Exception {
        this.item = item;       
        initMapping();              
        return (Output) extract();      
    }

    private void initMapping() {
        if (!areNamesSetup) {
            mapColumns();
        }
        areNamesSetup = true;
    }

    private void mapColumns() {     
        Field[] allFields = item.getClass().getDeclaredFields();
        for (Field field : allFields) {
            if (!field.getType().equals(Set.class) && Modifier.isPrivate(field.getModifiers())) {               
                names.add(field.getName());                 
            }
        }
    }   

    private Object extract() {
        List<Object> values = new ArrayList<Object>();
        BeanWrapper bw = new BeanWrapperImpl(item);     
        for (String propertyName : this.names) {                        
            values.add(bw.getPropertyValue(propertyName));          
        }       
        return StringUtils.collectionToDelimitedString(values, DELIMITER);      
    }   
}

表地址具有以下字段:

@ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="city_id", nullable=false)
    public City getCity() {
        return this.city;
    }

城市对应的列:

@Column(name="city_id", unique=true, nullable=false)
    public Short getCityId() {
        return this.cityId;
    }

当使用 values.add(bw.getPropertyValue(propertyName)); 且 propertyName 为“city”时,会发生以下异常:

org.hibernate.SessionException: proxies cannot be fetched by a stateless session
    at org.hibernate.internal.StatelessSessionImpl.immediateLoad(StatelessSessionImpl.java:292)
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:156)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:260)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:68)
    at nl.sander.mieras.localhost.sakila.City_$$_jvstc2c_d.toString(City_$$_jvstc2c_d.java)
    at java.lang.String.valueOf(String.java:2982)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at org.springframework.util.StringUtils.collectionToDelimitedString(StringUtils.java:1132)
    at org.springframework.util.StringUtils.collectionToDelimitedString(StringUtils.java:1148)
    at nl.sander.mieras.processor.DynamicRecordProcessor.extract(DynamicRecordProcessor.java:52)
    at nl.sander.mieras.processor.DynamicRecordProcessor.process(DynamicRecordProcessor.java:27)

但是,该值是可用的,如下面的屏幕截图所示。 enter image description here

具体问题:如何获得值 300?

我尝试使用反射 API 获取值,但无法达到我想要获取的实际值...

重现

我已经设置了一个公共(public)存储库。但是,您仍然需要本地数据库才能准确重现问题。 https://github.com/Weirdfishees/hibernate-batch-example 。我们非常欢迎任何关于如何进一步隔离此问题的建议。

最佳答案

只需使用 useStatelessSession 属性将您的阅读器切换为全状态而不是无状态:

<!-- Standard Spring Hibernate Reader -->
<bean id="hibernateItemReader" class="org.springframework.batch.item.database.HibernateCursorItemReader">
    <property name="sessionFactory" ref="sessionFactory" />         
    <property name="queryString" value="from Address" />
    <property name="useStatelessSession" value="false" />       
</bean> 

关于java - 如何使用 Spring Batch 和 Hibernate 从 @JoinColumn 获取值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36893089/

相关文章:

java - IndexOutOfBounds - 需要帮助

java - 将 ListView 和 ArrayAdapter 传递给另一个类

java - ObjectOutputStream.writeObject 到文件线程安全吗?

java - Spring:如何从jar类路径加载@ContextConfiguration?我收到 FileNotFoundException

java - 使用intellij idea 13社区版创建基本的spring核心应用程序

java - Eclipse Design Tab 检测到错误的 Java

java - Spring Tomcat 出现 Mysql 数据库错误

postgresql - 如何将一组 ID 映射到 Hibernate 中的其他表?

java - Spring MVC Hibernate 没有具有可用于当前线程的实际事务的 EntityManager - 无法可靠地处理 'persist' 调用

java - 使用 Spring MVC 和 Hibernate 在 Multi-Tenancy 数据库应用程序中动态添加租户