【问题标题】:Batch insertion with Spring MVC and Hibernate 3使用 Spring MVC 和 Hibernate 3 进行批量插入
【发布时间】:2014-10-01 07:53:38
【问题描述】:

我正在使用 Spring MVC + Hibernate 并尝试使用“休眠批处理技术”保存批量记录,但在执行 session.flush()session.clear() 时遇到异常。

org.hibernate.LazyInitializationException: 无法初始化代理 - 没有会话

以下是我的代码示例

  1. DaoImpl 方法

        @SuppressWarnings("unchecked")
            @Override
            public String transferPsalesDataToMisSales() {  
                Session session = null;
                Transaction tx=null;
                String result="failed";         
                try {session = this.getSessionFactory().openSession();          
                    tx = session.beginTransaction();                        
                    Criteria criteria=session.createCriteria(PsalesInfo.class);         
                    List<PsalesInfo> pSalesData=criteria.list();                
                    if(pSalesData.size() >0){               
                        Iterator<PsalesInfo> it=pSalesData.iterator();
                        int index=0;
                        MisSalesInfo mis=null;
                        while(it.hasNext()){
                            mis=new MisSalesInfo();
                            PsalesInfo psales=it.next();                        
                            StockistInfo stockistInfo=psales.getStockistInfo();
                            TalukaInfo talukaInfo=stockistInfo.getTalukaInfo();                     
                            IsrInfo isr=(IsrInfo) session.get(IsrInfo.class, stockistInfo.getIsrId());                      
                            //mis settters
                            mis.setMisSalesId(psales.getPsalesId());                        
                            mis.setStateName(talukaInfo.getDistrictInfo().getStateInfo().getStateName());                       
                            mis.setDistName(talukaInfo.getDistrictInfo().getDistName());                        
                            mis.setTalukaName(talukaInfo.getTalukaName());                                  
                            mis.setAsmId(talukaInfo.getAsmInfo().getAsmId());                       
                            mis.setTsoId(stockistInfo.getTsoInfo().getTsoId());                 
                            if(null!=isr){
                                mis.setIsrId(isr.getIsrId());
                                mis.setIsrName(isr.getIsrName());                           
                            }
                            mis.setUnitNo(stockistInfo.getUnitNo());                    
                            mis.setBillNo(psales.getBillNo());              
                            session.save(mis);                      
                            if(index % 50==0){
                                //flush a batch of inserts and release memory:
                                session.flush();
                                session.clear();
                            }
                            index++;
                        }//end of while         
                        tx.commit();                
                        result=pSalesData.size()+" Psales are Successfully transfered to MIS Sales";                
                    }
                    else{
                        result="No Psales is available to transfer since  are already available in MIS Sales";
                    }           
                } catch (HibernateException e) {
                    tx.rollback();          
                    logger.error("error  in MasterDaoImpl transfer data:"+e);           
                }finally {
                    if (null != session)
                        session.close();
                }
                return result;
            }
    
  2. POJO

            @Entity
            @Table(name = "psales_info", catalog = "secondary_sales")
            public class PsalesInfo implements java.io.Serializable {   
                private static final long serialVersionUID = 5578632011679493005L;
                private Integer psalesId;
                private StockistInfo stockistInfo;
                //and some other attributes
              //getter and setters
            @Id
                @GenericGenerator(name="generator", strategy="increment")
                @GeneratedValue(generator="generator")
                @Column(name = "psales_id", unique = true, nullable = false)
                public Integer getPsalesId() {
                    return this.psalesId;
                }
    
                public void setPsalesId(Integer psalesId) {
                    this.psalesId = psalesId;
                }
    
                @ManyToOne(fetch = FetchType.LAZY)
                @JoinColumn(name = "pcode", nullable = false)
                public StockistInfo getStockistInfo() {
                    return this.stockistInfo;
                }
        //and others
    
    @Entity
    @Table(name = "stockist_info", catalog = "secondary_sales")
    public class StockistInfo implements java.io.Serializable {
        private String stockistId;
        private TalukaInfo talukaInfo;
    //and rest attributes
    //getters and setters
    // Property accessors
        @Id 
        @Column(name = "stockist_id", unique = true, nullable = false, length = 10)
        public String getStockistId() {
            return this.stockistId;
        }
    
        public void setStockistId(String stockistId) {
            this.stockistId = stockistId;
        }
    
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "taluka_sid", nullable = false)
        public TalukaInfo getTalukaInfo() {
            return this.talukaInfo;
        }
    
  3. 服务实现

    @Service @Transactional public class TransactionServiceImpl implements TransactionService { @Autowired private TransactionDAO transactionDAO;
    @Override
    public String transferPsalesDataToMisSales() {      
        return this.getTransactionDAO().transferPsalesDataToMisSales();
    }
    
    }
  4. dispature-servlet.xml

    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="configLocation" value="classpath:hibernate.cfg.xml"/>
        <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration"/>
    
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>             
                <prop key="hibernate.default_catalog">${hibernate.default_catalog}</prop>
                <prop key="hibernate.jdbc.batch_size">50</prop>                                         
            </props>
        </property>
    </bean>
    
    <tx:annotation-driven transaction-manager="transactionManager"/> 
    
    <bean id="transactionManager" 
          class="org.springframework.orm.hibernate3.HibernateTransactionManager" 
          p:sessionFactory-ref="sessionFactory"/>
    

这里需要帮助,为什么当我清除会话时它会抛出 LazyInitializationException。

但是当我没有清除会话时,即。 session.clear()session.flush() 应用程序运行正常。

但我知道如果有更多批量记录,它可能会导致OutOfMemoryException

所以请告诉现在如何处理这种情况?

【问题讨论】:

    标签: spring hibernate spring-mvc batch-processing lazy-initialization


    【解决方案1】:

    您的 dao 代码有缺陷...不要自己打开新会话,也不要自己搞乱事务。从您的 dao 方法中删除事务内容,并且对 openSession 的调用应替换为 getCurrentSession

    @SuppressWarnings("unchecked")
    @Override
    public String transferPsalesDataToMisSales() {  
        Session session = this.getSessionFactory().getCurrentSession();
        Criteria criteria=session.createCriteria(PsalesInfo.class);         
        List<PsalesInfo> pSalesData=criteria.list();                
        int index=0;
    
        for (PsalesInfo psales : pSalesData) {
            MisSalesInfo mis=new MisSalesInfo();
            StockistInfo stockistInfo=psales.getStockistInfo();
            TalukaInfo talukaInfo=stockistInfo.getTalukaInfo();                     
            IsrInfo isr=(IsrInfo) session.get(IsrInfo.class, stockistInfo.getIsrId());                      
            //mis settters
            mis.setMisSalesId(psales.getPsalesId());                        
            mis.setStateName(talukaInfo.getDistrictInfo().getStateInfo().getStateName());                       
            mis.setDistName(talukaInfo.getDistrictInfo().getDistName());                        
            mis.setTalukaName(talukaInfo.getTalukaName());                                  
            mis.setAsmId(talukaInfo.getAsmInfo().getAsmId());                       
            mis.setTsoId(stockistInfo.getTsoInfo().getTsoId());                 
            if(null!=isr){
                mis.setIsrId(isr.getIsrId());
                mis.setIsrName(isr.getIsrName());                           
            }
            mis.setUnitNo(stockistInfo.getUnitNo());                    
            mis.setBillNo(psales.getBillNo());              
            session.save(mis);                      
            if(index % 50==0){
                //flush a batch of inserts and release memory:
                session.flush();
                session.clear();
            }
            index++;
        }//end of loop         
    
        if (pSalesData.isEmpty() ) {
             return "No Psales is available to transfer since  are already available in MIS Sales";
        } else {
            return pSalesData.size()+" Psales are Successfully transfered to MIS Sales";                
        }
    }
    

    【讨论】:

    • 嗨,Deinum,感谢您的回复!!!正如你所说的使用 getCurrentSession ..我做了,但没有抛出任何会话异常......在我的整个应用程序中,我们使用 this.getsessionFactory.openSession() 进行会话并在函数结束后关闭。所以当前会话不可用我的东西..请告诉我替代方案..
    • 不要使用opensession!这基本上使 springs tx 支持无用。如果没有活动会话,则表明您的 tx 设置错误。修复它而不是尝试使用opensession 来解决它。
    • 你能给我任何参考吗?使用 org.springframework.orm.hibernate3.HibernateTransactionManager 我在我的 daoImpl 上使用 @autowired SessionFactory sessionFactory
    • 理想情况下应该在包含您的服务的上下文中。我的猜测是那些在ContextLoaderListener而不是DispatcherServlet加载的上下文中。
    • 我现在明白你的意思了......但仍然有一个疑问......告诉我如果我们使用 .getCurrentSession() 而不是 .openSession() 那么何时何地关闭该会话?据我所知,在 sessionFactory 中,我们一次可以有有限数量的会话......所以对于 daoImpl 类中的每个函数,我们通过 .getCurrentSession 获取会话对象但没有关闭,这可能导致会话工厂中多个会话对象的异常对?如果它是由 spring 管理的,请告诉我,那么我将在我使用 .openSession() 的地方更改我的项目结构,我将使用 .getCurrentSession()
    猜你喜欢
    • 2012-03-31
    • 2014-11-14
    • 2018-10-22
    • 2016-03-17
    • 2011-12-14
    • 2011-02-15
    • 1970-01-01
    • 1970-01-01
    • 2020-03-26
    相关资源
    最近更新 更多