当前位置: 首页 > 知识库问答 >
问题:

如何使用Spring batch和Hibernate从@JoinColumn中获取值

东云
2023-03-14

为了从数据库中提取一些数据,我试图设置一个基本的hibernate和spring批处理项目。目标是提供一个查询(HQL),并基于该查询,spring batch应用程序将所有数据提取到一个平面文件中。

应用程序的一个要求是,用户不必配置列的映射。因此,我试图创建一个DynamicRecordProcessor,它计算输入并将输入(表,例如Address),以平面文件项编写器可以使用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)

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

我已经设置了一个公开回购。但是,您仍然需要一个本地数据库来准确地再现问题。https://github.com/weirdfishees/hibernate-batch-example。任何关于如何进一步隔离这个问题的建议都是非常受欢迎的。

共有1个答案

郏志学
2023-03-14

只需使用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> 
 类似资料:
  • 问题内容: 我已经阅读了很多有关@JoinColumn的内容,但是我仍然不明白它的含义。 患者表 车辆表 患者分类 车辆类别 Vehicle Class ---- Entity @JoinColumn(name=”patient_id”) ---- annotation private Patient patient ----field ``` 会说吗?该车辆实体有一个外键到患者实体命名patie

  • 我读了很多关于@JoinColumn的文章,但我仍然不明白它背后的想法。 病人床 车辆表 我一直在读这篇文章,但我仍然感到困惑。JPA JoinColumn与mappedBy

  • 最近,我在使用标准应用编程接口时遇到了问题。这是我第一次接触它。这是我的办公室实体的一部分。 目标-从特定的办公室实体获取工人实体列表。到目前为止,我已经知道如何通过以下方式实现目标: 它工作得很好,但我认为我太依赖JavaList接口方法而不是CriteriaAPI。我可以通过在Criteria中创建适当的查询来获取WorkerEntity(OfficeEntity中的字段“workers”)列

  • 问题内容: 在日志中,我得到: “来自LAHETYS”发生了什么事?使用HQL或/和SQL处理此问题的最佳实践是什么? 另一个问题: 我得到一个例外: 所以我不能将对象投射到我的Lahetys对象上,很奇怪吗? 谢谢!佐美 问题答案: 您的HQL查询无效。LIMIT不是有效的HQL子句。要在Hibernate中做到这一点,只需

  • 我想返回此SQL Postgis查询的输出(几何类型中的输出为“0101000000000000000002440000000000002440”) 用Java和hibernate。 我尝试了以下方法: 这对我不起作用。我得到以下异常 我想我明白问题是什么。我尝试将结果解析为字符串,但它是几何对象。但是我该怎么做才能在 Java 中将此输出作为字符串获取?如果我只在 SQL 查询后面添加 .lis

  • 我有一个实体类具有以下主键生成策略 我想知道是否有一种方法可以使用EntityManager向表生成器询问下一个值。