2012-03-15 25 views
5

La mia applicazione è basata su Hibernate 3.2 e Spring 2.5. Ecco la gestione delle transazioni relative frammento dal contesto di applicazione:Inserimenti batch con sospensione e molla

<tx:annotation-driven transaction-manager="txManager"/> 
    <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
      <property name="sessionFactory" ref="sessionFactory"/> 
      <property name="nestedTransactionAllowed" value="true"/> 
    </bean> 
    <bean id="transactionTemplate" classs="org.springframework.transaction.support.TransactionTemplate"> 
      <property name="transactionManager" ref="txManager"/> 
    </bean> 
    <bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/> 
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 
    <property name="configLocation" value="classpath:/hibernate.cfg.xml"></property> 
    </bean> 

Per tutto il ci sono rilevanti classe di servizio e le transazioni sono gestite lì con @Transactional su ogni metodo nel livello di servizio DAO. Tuttavia c'è uno scenario ora che un metodo in DAO dice "parse()" viene chiamato dal livello di servizio. Nel livello di servizio ho specificato @Transactional(readOnly=false). Questo metodo di analisi nel DAO chiama un altro metodo dire "save()" nello stesso DAO che memorizza un numero elevato di righe (circa 5000) nel database. Ora il metodo di salvataggio è chiamato in un ciclo dalla funzione parse. Ora il problema è che dopo circa 100 chiamate al metodo "salva" ... a volte ottengo un'eccezione OutOfMemory o talvolta il programma smette di rispondere.

Per ora queste sono le modifiche che ho fatto per il metodo di salvataggio:

Session session = getHibernateTemplate().getSessionFactory().openSession(); 
      Transaction tx = session.beginTransaction(); 

      int counter = 0; 
      if(books!=null && !books.isEmpty()){ 
       for (Iterator iterator = books.iterator(); iterator 
         .hasNext();) { 
        Book book = (Book) iterator.next(); 
        session.save(book); 
        counter++; 
        if(counter % 20==0) { 
         session.flush(); 
         session.clear(); 
        } 
       } 
      } 
      tx.commit(); 
     session.close(); 

Questo è l'unico metodo nella mia applicazione in cui mi metto una transazione come questo e commetto alla fine del metodo. Altrimenti normalmente chiamano solo getHibernateTemplate.save(). Non sono sicuro se dovrei eseguire la gestione delle transazioni per questo metodo di salvataggio separatamente nel DAO posizionando @Transactional(readOnly=false, PROPOGATION=NEW) su save(), oppure questo approccio è corretto?

Inoltre ho aggiornato hibernate.jdbc.batch_size su 20 nel file di configurazione hibernate.cfg.

Qualche suggerimento?

risposta

0

Mi rifarei parse in un modo che non chiama save direttamente ma richiede alcune richiamate dal livello di servizio. Il livello di servizio passerebbe il suo metodo transazionale con la chiamata save come questa richiamata.

Potrebbe non funzionare esattamente come descritto nel tuo caso ma da questa breve descrizione questo sarebbe qualcosa che proverei.

1

È necessario solo il bit con lo svuotamento e la pulizia della sessione. Lascia la gestione delle transazioni a Spring. Usa sessionFactory.getCurrentSession() per raggiungere la sessione che Spring ha già aperto per te. Inoltre, la recente raccomandazione di Spring è di evitare HibernateTemplate e lavorare direttamente con l'API di Hibernate. Inietta SessionFactory sul tuo dao-bean.

5

per l'inserimento batch con Hibernate, la pratica migliore è StatelessSession, `t del doesn memorizza nella cache tutti i membri della vostra entità, non si incontrano OutOfMemory, il codice come:

if (books == null || books.isEmpty) { 
    return; 
} 
StatelessSession session = getHibernateTemplate().getSessionFactory().openStatelessSession(); 
Transaction tx = session.beginTransaction(); 

for (Book each : books) {   
    session.insert(book);   
} 
tx.commit(); 
session.close(); 

e la transazione di StatelessSession è indipendente dal contesto corrente della transazione.

Problemi correlati