Results 1 to 6 of 6

Thread: Unable to get @Transactional working

  1. #1
    Join Date
    Oct 2005
    Posts
    4

    Default Unable to get @Transactional working

    All,

    My app runs on JDK 1.5, Hibernate 3.0.5 and Spring 1.2.5

    I've been unable to get the @Transactional attribute working.

    The relevant part of my spring configuration is below:
    Code:
        <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
            <property name="sessionFactory" ref="sessionFactory"/>
        </bean>
    
        <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
    
        <bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
            <property name="transactionInterceptor" ref="transactionInterceptor"/>
        </bean>
    
        <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
            <property name="transactionManager" ref="txManager"/>
            <property name="transactionAttributeSource">
                <bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"/>
            </property>
        </bean>
    My code looks like this:
    Code:
    public interface MyCrudService &#123;
       @Transactional
       public void create&#40;MyObject object&#41;;
    &#125;
    and the implementation is:
    Code:
    public class DefaultMyCrudService implements MyCrudService &#123;
       public void create&#40;MyObject object&#41; &#123;
             currentSession&#40;&#41;.save&#40;object&#41;;
       &#125;
    &#125;
    The currentSession() method obtains a hibernate session that has it's flush mode set to AUTO. However, if I don't use the annotation, and instead use an implementation like the one below, my tests pass:

    Code:
    public class DefaultMyCrudService implements MyCrudService &#123;
       public void create&#40;MyObject object&#41; &#123;
             Transaction transaction = currentSession&#40;&#41;.beginTransaction&#40;&#41;;
             currentSession&#40;&#41;.save&#40;object&#41;;
             transaction.commit&#40;&#41;;
       &#125;
    &#125;
    For my tests, I obtain the service from spring, so I'm sure that it will get advised correctly by the TransactionInterceptor.

    Am I doing something wrong here?

  2. #2
    Join Date
    May 2005
    Location
    San Francisco
    Posts
    61

    Default

    hi, pls post complete code for MyCrudService implementation. Currently it's missing the source for currentSession() method. Other than possible problems in this method, i don't see any other issues in your code.

  3. #3
    Join Date
    Oct 2005
    Posts
    4

    Default Here's the source code for the currentSession method

    Basically, MyCrudService has a session-per-thread implementation.
    I think the problem is defintely here - do I have to use SessionFactoryUtils to obtain a hibernate session?

    Code:
    public class MyCrudService &#123;
        private SessionFactory sessionFactory;
        private static ThreadLocal<Session> sessions = new ThreadLocal<Session>&#40;&#41;;
    
        public MyCrudService&#40;SessionFactory factory&#41;&#123;
            sessionFactory = factory;
        &#125;
    
        public void create&#40;MyObject object&#41; &#123;
            currentSession&#40;&#41;.save&#40;object&#41;;
        &#125; 
    
        private Session currentSession&#40;&#41; &#123;
            if &#40;sessions.get&#40;&#41; == null&#41; &#123;
                sessions.set&#40;sessionFactory.openSession&#40;&#41;&#41;;
            &#125;
            return &#40;Session&#41; sessions.get&#40;&#41;;
        &#125;
    
        public void closeSession&#40;&#41; &#123;
            if &#40;sessions.get&#40;&#41;!= null&#41; &#123;
                closeCurrentSession&#40;&#41;;
                clearSession&#40;&#41;;
            &#125;
        &#125;
    
        private void closeCurrentSession&#40;&#41; &#123;
            currentSession&#40;&#41;.flush&#40;&#41;;
            currentSession&#40;&#41;.close&#40;&#41;;
        &#125;
    
        void clearSession&#40;&#41; &#123;
            sessions.remove&#40;&#41;;
        &#125;
    &#125;

  4. #4
    Join Date
    May 2005
    Location
    San Francisco
    Posts
    61

    Default

    Keeping session in the thread's context is redundant as it's what essentially done by transactional context. In certain cases it might be dangerous too. In your particular case, I believe, you loose transactional context b/c you simply open new session w/o consulting SessioFactoryUtils which is .

    The normal workflow how you normally use SessionFactory/Session in Spring is:

    Code:
    public void setSessionFactory&#40;SessionFactory sessionFactory&#41; &#123;
      this.hibernateTemplate = new HibernateTemplate&#40;sessionFactory&#41;;
    &#125;
    
    public void create&#40;MyObject object&#41; &#123;
      hibernateTemplate.execute&#40;
        new HibernateCallback&#40;&#41; &#123;
          public Object doInHibernate&#40;Session session&#41;  &#123;
             session.DO&#40;...&#41;;
             ...
             return null;
          &#125;
        &#125;
      &#41;;
    &#125;
    Alternatively (if you don't want to use template/callback) you can use SessionFactoryUtils for opening/releasing session to keep transactional context or extend HibernateDaoSupport.
    [/quote]

  5. #5
    Join Date
    May 2005
    Location
    San Francisco
    Posts
    61

    Default

    Another way, if you want to avoid using Spring's API altogether, is to setup transaction manager for DataSource and simply use:
    Code:
    Session = sessionFactory.openSession&#40;&#41;;
    try &#123;
      session.DO&#40;&#41;;
      ...
      session.flush&#40;&#41;;
    &#125; finally &#123;
      session.close&#40;&#41;;
    &#125;
    and let all transactions be handled on the DataSource level. This way is not completely correct from the standpoint of Hibernate's API, but it works. It also has worse performance as it potentially opens/closes session many times per transaction.

  6. #6
    Join Date
    May 2005
    Location
    San Francisco
    Posts
    61

    Default

    there's actually another better way to work with sessions in the transactional context:
    Code:
    public void create&#40;MyObject object&#41; &#123;
      sessionFactory.getCurrentSession&#40;&#41;.DO&#40;...&#41;;
    &#125;
    It also allows to avoid using Spring's API, but fully supports Spring's transaction management.

Similar Threads

  1. Jboss, JAAS, Spring -- working example?
    By jkwon in forum Security
    Replies: 4
    Last Post: May 14th, 2009, 03:41 PM
  2. Replies: 1
    Last Post: Jan 20th, 2009, 11:50 AM
  3. Beandoc crashing (on its samples!)
    By aaime in forum Container
    Replies: 17
    Last Post: Oct 7th, 2005, 07:21 AM
  4. Replies: 1
    Last Post: Oct 6th, 2005, 10:32 AM
  5. PerformanceMonitorInterceptor
    By tnist in forum AOP
    Replies: 3
    Last Post: Aug 24th, 2005, 01:39 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •