2010-01-18 17 views
6

Mam aplikację internetową z ustawieniem Spring, aby utworzyć moją fabrykę sesji hibernacji (singleton) oraz sesję i transakcję (obie są objęte zakresem żądania), ale to niszczy sesję i transakcji w złej kolejności. Jak mogę to skonfigurować, aby transakcja została zniszczona przed sesją? Oto moja wiosna applicationContext.xml file:Próba zniszczenia fasoli w prawidłowej kolejności przy użyciu Spring

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" 
     "http://www.springframework.org/dtd/spring-beans-2.0.dtd"> 
<beans> 
    <bean id="hibernateSessionFactory" scope="singleton" 
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 
    <property name="configLocation" value="classpath:hibernate.cfg.xml" /> 
    </bean> 

    <!-- The per-http request hibernate session --> 
    <bean id="hibernateSession" factory-bean="hibernateSessionFactory" 
    factory-method="openSession" destroy-method="close" scope="request" /> 

    <!-- The per-http request transaction (i need this to be destroyed BEFORE the session) --> 
    <bean id="hibernateTransaction" factory-bean="hibernateSession" 
    factory-method="beginTransaction" destroy-method="commit" scope="request" /> 
</beans> 

A oto log, który pokazuje to zamknięcie sesji przed zamknięciem transakcji:

16111 [http-8080-3] DEBUG org.springframework.beans.factory.support.DisposableBeanAdapter - Invoking destroy method 'close' on bean with name 'hibernateSession' 
16111 [http-8080-3] DEBUG org.hibernate.jdbc.ConnectionManager - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)] 
16111 [http-8080-3] DEBUG com.mchange.v2.resourcepool.BasicResourcePool - trace [email protected] [managed: 4, unused: 3, excluded: 0] (e.g. [email protected]) 
16111 [http-8080-3] DEBUG org.springframework.beans.factory.support.DisposableBeanAdapter - Invoking destroy method 'commit' on bean with name 'hibernateTransaction' 
16111 [http-8080-3] DEBUG org.hibernate.transaction.JDBCTransaction - commit 
16111 [http-8080-3] WARN org.springframework.beans.factory.support.DisposableBeanAdapter - Invocation of destroy method 'commit' failed on bean with name 'hibernateTransaction' 
org.hibernate.SessionException: Session is closed 

Odpowiedz

4

Wygląda na to, że kolejność wywoływania metod destory w przypadku ziaren o rozmiarze jednostajnym jest całkowicie poza kontrolą. Od docs (3.4.3 Using depends-on):

zależy na atrybut w definicji fasoli można określić zarówno czas inicjalizacja zależność i w przypadku pojedynczych ziaren wyłącznie, odpowiedni zniszczyć czas zależnościami

można utworzyć obiekt pomocnika i tworzenia delegata i zniszczenie swojego ziarna do niego:

public class HelperObject 
{ 
    private SessionFactory factory; 
    private Session session; 
    private Transaction tx; 

    public void init() 
    { 
     session = factory.createSession(); 
     tx = session.beginTransaction(); 
    } 

    public void destroy() 
    { 
     tx.commit(); 
     session.close(); 
    } 

    ... 
} 

-

<bean id = "helperObject" class = "HelperObject" scope = "request" init-method = "init" destroy-method = "destroy"> 
    <property name = "factory" ref = "hibernateSessionFactory" /> 
</bean> 

<bean id="hibernateSession" factory-bean="helperObject" 
    factory-method="getSession" scope="request" /> 

<bean id="hibernateTransaction" factory-bean="helperObject" 
    factory-method="getTransaction" scope="request" /> 

I, mimo wszystko, może to nie jest najlepszy sposób na zarządzanie sesji Hibernate i transakcje na wiosnę. Rozważ skorzystanie z wbudowanej w Springa obsługi Hibernate i transactions.

EDIT: Cóż, właściwa droga do zarządzania transakcjami jest:

  • Nie musisz Request-scoped session i transaction fasola
  • Nie należy zadzwonić na createSession fabryka sesji zwrócona przez org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean. Możesz wprowadzić tę fabrykę sesji do swoich ziaren i zadzwonić pod numer getCurrentSession, kiedy potrzebujesz sesji, a ona zadziała dobrze.
  • Można użyć deklaracji zarządzania transakcjami (@Transactional) w metodach transakcyjnych). Aby to działało, powinieneś dodać do swojej konfiguracji:

.

<bean id="transactionManager" 
    class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="hibernateSessionFactory"/> 
</bean> 

<tx:annotation-driven/> 
  • Aby uzyskać więcej informacji, patrz linki powyżej
+0

Witam, Podejrzewałem, że wiosna ma wbudowane opcje zarządzania sesją/txn, jednak po przeczytaniu tych dwóch linków nadal nie jestem bliżej zrozumienia, jak one działają. Myślę, że wybiorę opcję "klasy pomocniczej", to świetny pomysł. Myślę, że szkoda, że ​​wiosna nie może kontrolować porządku niszczenia, to naprawdę nie robi dla mnie tak wiele. – Chris

+0

Spojrzałem na te 2 linki i nie widziałem, jak mogłem skorzystać z wiosennego menedżera transakcji (lub cokolwiek innego), aby dać mi sesję i transakcję, którą mógłbym wstrzyknąć w moje działania, wydawało mi się, że tylko sesja fabryka, którą mógłbym wtedy nazwać 'getCurrentSession()', co dla mnie nie wygląda ładnie. – Chris

+0

Zgaduję, o co pytam, jeśli to nie jest najlepszy sposób, jaki * jest * najlepszy sposób zarządzania sesjami/txns ze sprężyną? – Chris

1

Można oświadczyć, że hibernateTransactiondepends-onhibernateSession. Ponieważ kontener będzie tworzył komponenty bean w kolejności zależności (blokując cykliczne zależności) i rozdzielił je w kolejności odwrotnej zależności, powinno to wystarczyć.

+1

Nie działa w przypadku ziaren o ograniczonym zasięgu. Zgodnie z dokumentacją, zależy od kolejności określającej kolejność niszczenia tylko dla ziaren o pojedynczej skali. – axtavt

+0

Tak, już wypróbowałem zależnie od tego, to nie pomogło. Jednak dzięki za odpowiedź! – Chris

1

transakcje powinny być związane z usługami, jeśli się wiosną idiom. Sesje są obiektami warstwy sieciowej, całkowicie oddzielonymi od warstwy usług.Wydaje mi się, że popełniłeś błąd polegający na uwikłaniu warstwy sieci w warstwę usług. Lepiej je rozczulać; jest mało prawdopodobne, aby ten problem dotyczył tego układu.

+0

Zrobiłem pół tuzina odczytów tego, aby dowiedzieć się, co masz na myśli! Zakładam teraz, że kiedy mówisz "usługa", masz na myśli klasy "biznesowe" (np. Klasy, które mają coś takiego jak "FindEventById()"). Więc usługi to te, które dbają o transakcje. Myślę, że to ma sens. – Chris

+0

Okay Próbowałem, co zasugerowałeś, ale teraz mam problem, że mój poziom usług ładuje mój obiekt zdarzenia w porządku, ale kiedy później próbuję uzyskać dostęp do pól w zwróconym obiekcie, ma on "LazyInitializationException - nie można zainicjować proxy - brak sesji ", prawdopodobnie dlatego, że sesja została zamknięta, ponieważ mój dostęp do warstwy usług został zakończony. Więc myślę, że sesja nadal musi być powiązana z zapytaniem w sieci, jakikolwiek sugestia, jak przezwyciężyłeś to? – Chris

+0

Ah-ha! Gotowy do pracy: potrzebny OpenSessionInViewFilter skonfigurowany w web.xml. Uff! – Chris

Powiązane problemy