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?