0

У меня есть приложение Java EE с Spring 3.1.1 и Hibernate 4.1. Теперь я хотел ускорить работу и увидел, что узким местом является открытие + закрытие нескольких транзакций в одном запросе.OpentransactionPerView вместо @Transactional

Теперь я удалил все @Transactional аннотации и создал свой собственный OpenSessionInViewFilter, который открывает и закрывает одну транзакцию.

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()); 
      } 
     } 
    } 
} 

Это хорошая идея? Кажется, он работает и ускоряет работу.

Вот мой журнал для сделок:

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=? 

пула соединений

<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> 

но открытое заседание в вид фильтра кажется закрыть сессии

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

Но даже если Я удаляю фильтр, Hibernate, похоже, не использует пул.

ответ

1

Я бы сказал, нет.

Например, вы сохраните какой-либо продукт или что-то еще в базе данных и покажете страницу успеха или перенаправляете, считая, что все было сохранено. Но транзакция еще не будет завершена и все еще может откат после вы получили сообщение об успешном завершении.

И с Hibernate вероятность этого события еще больше, потому что ничего не будет записано в базу данных до момента очистки, что произойдет непосредственно перед фиксацией.

Кроме того, транзакция будет жить дольше, чем необходимо, предотвращая другие транзакции для проверок в случае, если она заблокировала строки или таблицы в базе данных, что приведет к снижению производительности и масштабируемости.

Что случилось с установкой Spring OpenSessionInViewFilter по умолчанию, которая позволяет сеансу открывать, но по-прежнему использует короткие транзакции на уровне обслуживания? Почему ваши запросы открывают несколько транзакций? Моя проблема заключается в том, что вы выполняете слишком много вызовов от уровня пользовательского интерфейса до уровня обслуживания в одном запросе.

+0

Это верно, и каждая открытая транзакция требует около 200 мс = (>> Моя задача заключается в том, что вы выполняете слишком много вызовов от уровня пользовательского интерфейса до уровня обслуживания в одном запросе. – wutzebaer

+0

Что-то настроено неправильно где-то, если вам нужно 200 мс, чтобы открыть транзакцию. Правильно ли настроен пул подключений? Где эти 200 мс потрачены? Вы измерили? –

+0

да, добавлен фрагмент журнала, мне нужно 3 транзакции за запрос: весенняя безопасность для получения пользователя, мой собственный imnterceptor безопасности и обработчик останова, который на самом деле выполняет работу = ( – wutzebaer

0

Наконец я настроил мой бассейн правильного пути ... решение не было, чтобы добавить некоторые свойства C3P0 моей спящей конфигурации, я просто должен был теперь заменить мой DataSource-боб

<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> 

работает как шарм

 Смежные вопросы

  • Нет связанных вопросов^_^