0

J'ai une application Java EE avec Spring 3.1.1 et Hibernate 4.1. Maintenant, je voulais accélérer les choses et j'ai vu que le goulot d'étranglement est l'ouverture + la fermeture de plusieurs transactions en une seule requête.OpentransactionPerView au lieu @Transactional

Maintenant, j'ai supprimé toutes les annotations @Transactional et créé mon propre OpenSessionInViewFilter, qui ouvre et ferme une transaction.

package utils.spring; 

import java.io.IOException; 

import javax.servlet.FilterChain; 
import javax.servlet.ServletException; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

import org.hibernate.Session; 
import org.hibernate.SessionFactory; 
import org.springframework.orm.hibernate4.SessionFactoryUtils; 
import org.springframework.orm.hibernate4.SessionHolder; 
import org.springframework.orm.hibernate4.support.OpenSessionInViewFilter; 
import org.springframework.transaction.support.TransactionSynchronizationManager; 

public class CustomHibernateSessionViewFilter extends OpenSessionInViewFilter { 

    @Override 
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { 

     SessionFactory sessionFactory = lookupSessionFactory(request); 
     boolean participate = false; 

     if (TransactionSynchronizationManager.hasResource(sessionFactory)) { 
      // Do not modify the Session: just set the participate flag. 
      participate = true; 
     } else { 
      logger.debug("Opening Hibernate Session in OpenSessionInViewFilter"); 
      Session session = openSession(sessionFactory); 
      TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session)); 
        //BEGIN TRANSACTION 
      session.beginTransaction(); 
     } 

     try { 
      filterChain.doFilter(request, response); 
     } 

     finally { 
      if (!participate) { 
       SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory); 
          // COMMIT 
       sessionHolder.getSession().getTransaction().commit(); 
       logger.debug("Closing Hibernate Session in OpenSessionInViewFilter"); 
       SessionFactoryUtils.closeSession(sessionHolder.getSession()); 
      } 
     } 
    } 
} 

Est-ce une bonne idée? Cela semble fonctionner et accélérer les choses.

Voici mon journal pour les transactions:

http-bio-8080-exec-3 01/03/2013 11:25:20,947 | DEBUG | org.springframework.orm.hibernate4.HibernateTransactionManager | doGetTransaction | Found thread-bound Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction 
http-bio-8080-exec-3 01/03/2013 11:25:20,948 | DEBUG | org.springframework.orm.hibernate4.HibernateTransactionManager | getTransaction | Creating new transaction with name [by2.server.service.UserService.loadUserByUsername]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; '' 
http-bio-8080-exec-3 01/03/2013 11:25:20,948 | DEBUG | org.springframework.orm.hibernate4.HibernateTransactionManager | doBegin | Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] 
http-bio-8080-exec-3 01/03/2013 11:25:21,172 | DEBUG | org.springframework.orm.hibernate4.HibernateTransactionManager | doBegin | Exposing Hibernate transaction as JDBC transaction [[email protected]1e7b64f4[valid=true]] 
http-bio-8080-exec-3 01/03/2013 11:25:21,188 | DEBUG | org.hibernate.SQL | logStatement | select userentity_.userID as userID5_ from users userentity_ where userentity_.username=? 

pool de connexion

<dependency> 
     <groupId>org.hibernate</groupId> 
     <artifactId>hibernate-c3p0</artifactId> 
     <version>4.1.1.Final</version> 
    </dependency> 

<property name="hibernateProperties"> 
     <value> 
      hibernate.hbm2ddl.auto=update 
      hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect 
      hibernate.bytecode.use_reflection_optimizer=false 
      hibernate.max_fetch_depth=0 
      hibernate.c3p0.min_size=5 
      hibernate.c3p0.max_size=20 
      hibernate.c3p0.timeout=300 
      hibernate.c3p0.max_statements=50 
      hibernate.c3p0.idle_test_period=3000 
      </value> 
    </property> 

mais la session ouverte dans le filtre de vue semble fermer les sessions

finally { 
     if (!participate) { 
      SessionHolder sessionHolder = 
        (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory); 
      logger.debug("Closing Hibernate Session in OpenSessionInViewFilter"); 
      SessionFactoryUtils.closeSession(sessionHolder.getSession()); 
     } 
    } 

Mais même quand Je retire le filtre, Hibernate ne semble pas utiliser le pool.

Répondre

1

Je dirais que non. Par exemple, vous économiserez un produit ou n'importe quoi dans la base de données, et afficherez une page de succès ou une redirection, pensant que tout a été sauvegardé. Mais la transaction ne sera pas encore validée et pourrait toujours annuler après vous avez affiché le message de réussite. Et avec Hibernate, la probabilité que cela se produise est encore plus grande, parce que rien ne sera écrit dans la base de données tant que le flush n'aura pas lieu avant la validation. De plus, la transaction durera plus longtemps que nécessaire, empêchant d'autres transactions de se déclencher si elle place un verrou sur des lignes ou des tables de la base de données, ce qui entraîne des performances et une évolutivité plus médiocres.

Qu'est-ce qui ne va pas avec Spring OpenSessionInViewFilter par défaut, qui permet à la session d'ouvrir, mais qui utilise toujours des transactions courtes au niveau du service? Pourquoi vos demandes ouvrent-elles plusieurs transactions? Mon problème est que vous faites trop d'appels de la couche d'interface utilisateur à la couche de service dans une seule requête.

+0

ce droit, et chaque transaction ouverte a besoin d'environ 200ms = (>> Ma queue est que vous faites trop d'appels de la couche de l'interface utilisateur à la couche de service dans une seule demande – wutzebaer

+0

Quelque chose est mal configuré quelque part si vous avez besoin 200ms juste pour ouvrir une transaction Le pool de connexion est-il configuré correctement? Où sont passés ces 200ms? Avez-vous mesuré? –

+0

oui, ajouté un extrait de journal, j'ai besoin de 3 transactions par requête: sécurité de printemps pour obtenir l'utilisateur, mon propre sécurité imnterceptor, et le reste gestionnaire qui fait le travail = ( – wutzebaer

0

Enfin j'ai configuré ma piscine de la bonne façon ... la solution est de ne pas ajouter des propriétés de c3p0 à ma config de mise en veille prolongée, je devais juste remplacer mon datasource-haricot

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" 
destroy-method="close"> 
    <!-- Connection properties --> 
    <property name="driverClass" value="org.postgresql.Driver" /> 
    <property name="jdbcUrl" value="jdbc:postgresql://localhost:5432/DBNAME" /> 
    <property name="user" value="xxx" /> 
    <property name="password" value="xxx" /> 
    <!-- Pool properties --> 
    <property name="minPoolSize" value="5" /> 
    <property name="maxPoolSize" value="20" /> 
    <property name="maxStatements" value="50" /> 
    <property name="idleConnectionTestPeriod" value="3000" /> 
    <property name="loginTimeout" value="300" /> 
</bean> 

fonctionne comme un charme maintenant