Results 1 to 5 of 5

Thread: Can't Use Raw Hibernate3 API in Spring-Managed Transaction?

  1. #1
    Join Date
    Nov 2008
    Location
    San Francisco, CA
    Posts
    14

    Question Can't Use Raw Hibernate3 API in Spring-Managed Transaction?

    In the Manual and JavaDoc, Spring explicit states that it plays really well with Hibernate's Contextual Sessions feature. Namely, that when you configure DataSource, Transactions, and Session lifecycle management with Spring, it ties into this Contextual Sessions feature.

    But I can't get it to work that way...

    /org/example/blogroll/applicationContext.xml
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans ...>
               
       <bean id="blogroll" class="org.example.blogroll.BlogRollImpl">
         <property name="dao" ref="blogEntryDAO" />
         <property name="txMgr" ref="blogRollTxMgr" />
       </bean>
       
       <bean id="blogEntryDAO" class="org.example.blogroll.BlogEntryDAO">
         <property name="sessionFactory" ref="sessionFactory" />
       </bean>
             
       <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
         <property name="configLocation" value="classpath:hibernate.cfg.xml" />
         <property name="dataSource" ref="blogRollDS" />
       </bean>
       
       <bean id="blogRollDS" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
         <property name="driverClassName" value="org.apache.derby.jdbc.ClientDriver"/>
         <property name="url" value="jdbc:derby://localhost:1527/BlogDB" />
       </bean>
       
       <bean id="blogRollTxMgr" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
         <property name="sessionFactory" ref="sessionFactory" />
       </bean>
       
     </beans>
    hibernate.cfg.xml
    Code:
    <!DOCTYPE hibernate-configuration PUBLIC
            "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
            "...">
    
    <hibernate-configuration>
    
        <session-factory>
            <!-- SQL dialect -->
            <property name="dialect">org.hibernate.dialect.DerbyDialect</property>
    
            <!-- Enable Hibernate's automatic session context management -->
            <property name="hibernate.current_session_context_class">thread</property>
    
            <!-- Disable the second-level cache  -->
            <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
    
            <!-- Echo all executed SQL to stdout -->
            <property name="show_sql">true</property>
    
            <mapping resource="org/example/blogroll/BlogEntry.hbm.xml"/>
    
        </session-factory>
    
    </hibernate-configuration>
    Main.java
    Code:
    package org.example.blogroll;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Main {
    
    	/**
    	 * @param args
    	 */
    	public static void main(String[] args) {
    		ApplicationContext appCtx = new ClassPathXmlApplicationContext("/org/example/blogroll/applicationContext.xml");
    		
    		BlogRollFacade blogroll = (BlogRollFacade) appCtx.getBean("blogroll");
    		BlogEntry entry = blogroll.getBlogEntry(1L);
    		
    		System.out.println("\"" + entry.getTitle() + "\" by "
    				+ entry.getAuthor() + " on " + entry.getDate());
    		System.out.println(entry.getBody());
    
    	}
    }
    BlogRollImpl.java (my service class)
    Code:
    package org.example.blogroll;
    
    import org.hibernate.Session;
    import org.springframework.orm.hibernate3.HibernateTransactionManager;
    import org.springframework.transaction.TransactionStatus;
    import org.springframework.transaction.support.DefaultTransactionDefinition;
    
    public class BlogRollImpl implements BlogRollFacade {
    
    	private BlogEntryDAO dao;
    	private HibernateTransactionManager txMgr;
    
    	public BlogRollImpl() {
    	}
    
    	public BlogEntry getBlogEntry(long id) {
    		BlogEntry entry;
    
    		TransactionStatus txStatus = txMgr.getTransaction(new DefaultTransactionDefinition());
    		try {
    			entry = dao.getEntry(id);
    		} catch (Exception ex) {
    			txMgr.rollback(txStatus);
    			throw new RuntimeException("Failed to get BlogEntry with id = "
    					+ id + "; rolling back transaction.", ex);
    		}
    		txMgr.commit(txStatus);
    
    		return entry;
    	}
    
    	public long saveBlogEntry(BlogEntry entry) {
    		throw new RuntimeException("saveBlogEntry() is not yet implemented.");
    	}
    
    	public BlogEntryDAO getDao() {
    		return dao;
    	}
    
    	public void setDao(BlogEntryDAO dao) {
    		this.dao = dao;
    	}
    
    	public HibernateTransactionManager getTxMgr() {
    		return txMgr;
    	}
    
    	public void setTxMgr(HibernateTransactionManager txMgr) {
    		this.txMgr = txMgr;
    	}
    
    }
    BlogEntryDAO.java
    Code:
    package org.example.blogroll;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    
    public class BlogEntryDAO {
    
    	private SessionFactory sessionFactory;
    	
    	public BlogEntry getEntry(Long id) {
    		Session session = sessionFactory.getCurrentSession();
    		
    		BlogEntry entry = (BlogEntry) session.get(BlogEntry.class, id);
    		
    		return entry;
    	}
    
    	public SessionFactory getSessionFactory() {
    		return sessionFactory;
    	}
    
    	public void setSessionFactory(SessionFactory sessionFactory) {
    		this.sessionFactory = sessionFactory;
    	}
    }
    and I get the following exception:

    Code:
    Exception in thread "main" java.lang.RuntimeException: Failed to get BlogEntry with id = 1; rolling back transaction.
    	at org.example.blogroll.BlogRollImpl.getBlogEntry(BlogRollImpl.java:26)
    	at org.example.blogroll.Main.main(Main.java:15)
    Caused by: org.hibernate.HibernateException: get is not valid without active transaction
    	at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:338)
    	at $Proxy1.get(Unknown Source)
    	at org.example.blogroll.BlogEntryDAO.getEntry(BlogEntryDAO.java:13)
    	at org.example.blogroll.BlogRollImpl.getBlogEntry(BlogRollImpl.java:23)
    	... 1 more


    However, if I use the SessionFactoryUtils class.......it works.

    BlogEntryDAO.java (now using SessionFactoryUtils)
    Code:
    package org.example.blogroll;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.springframework.orm.hibernate3.SessionFactoryUtils;
    
    public class BlogEntryDAO {
    
    	private SessionFactory sessionFactory;
    	
    	public BlogEntry getEntry(Long id) {
    		Session session = SessionFactoryUtils.getSession(sessionFactory, false);
    		
    		BlogEntry entry = (BlogEntry) session.get(BlogEntry.class, id);
    		
    		return entry;
    	}
    
    	public SessionFactory getSessionFactory() {
    		return sessionFactory;
    	}
    
    	public void setSessionFactory(SessionFactory sessionFactory) {
    		this.sessionFactory = sessionFactory;
    	}
    }
    I get successful output:

    Code:
    Hibernate: select blogentry0_.ID as ID0_0_, blogentry0_.title as title0_0_, blogentry0_.author as author0_0_, blogentry0_.body as body0_0_, blogentry0_.CREATED_ON as CREATED5_0_0_ from BLOG_ENTRIES blogentry0_ where blogentry0_.ID=?
    "This is our first Persisted Blog Entry" by SYSTEM on 2008-11-02 21:12:30.0
    This is the first blog entry that we actually pulled from the database...cool!
    Any ideas as to why? Am I missing something fundamental here?


    p.s. I had to remove URL-style URIs in the XML config... you can't post URLs until ya got 5 posts under your belt...soon!
    Last edited by jtigger; Nov 9th, 2008 at 11:16 PM. Reason: Accidentally submitted!

  2. #2
    Join Date
    Jun 2006
    Location
    The Netherlands
    Posts
    13,624

    Default

    1) Don't start transactions yourself, configure them
    2) Don't override the 'hibernate.current_session_context_class' only do this in case of JTA
    Code:
    <hibernate-configuration>
    
        <session-factory>
            <!-- SQL dialect -->
            <property name="dialect">org.hibernate.dialect.DerbyDialect</property>
    
            <!-- Enable Hibernate's automatic session context management -->
            <property name="hibernate.current_session_context_class">thread</property>
    
            <!-- Disable the second-level cache  -->
            <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
    
            <!-- Echo all executed SQL to stdout -->
            <property name="show_sql">true</property>
    
            <mapping resource="org/example/blogroll/BlogEntry.hbm.xml"/>
    
        </session-factory>
    
    </hibernate-configuration>
    3. Just a hint for production use don't use the DriverManagerDataSource in production, use a proper connection pool.
    Marten Deinum
    Java Consultant / Pragmatist / Open Source Enthousiast / Author


    Pro Spring MVC: With Web Flow
    Conspect

    Have you read the reference guide.
    Use the [ code ] tags, young padawan

  3. #3
    Join Date
    Nov 2008
    Location
    San Francisco, CA
    Posts
    14

    Default

    1) Don't start transactions yourself, configure them
    Yeah, I was playing around with explicitly starting the transaction. In the "real world" I'd use declarative transactions. But isn't this exactly the kind of code the transaction proxy would execute to start the transaction? Totally with ya, here.

    2) Don't override the 'hibernate.current_session_context_class' only do this in case of JTA
    Interesting. What does overriding, here do? Isn't thread-local contextual sessions the default? Does specifying this change something?

    3. Just a hint for production use don't use the DriverManagerDataSource in production, use a proper connection pool.
    *grin* Absolutely! This is a little toy example.


    Thanks for the tips. I'm fishing for some insight into how Spring is attempting to play nicely with Hibernate's contextual sessions mechanism. Both are storing sessions in ThreadLocal (in very similar ways)... Minus the explicit transaction schtuffs, this is what I've pieced together as an example from the manual. But... the Spring doesn't seem to be syncing-up with the Hibernate Session... any thoughts on why that might be?

  4. #4
    Join Date
    Jun 2006
    Location
    The Netherlands
    Posts
    13,624

    Default

    Interesting. What does overriding, here do? Isn't thread-local contextual sessions the default? Does specifying this change something?
    It basically disables the spring integration for hibernate. There is a SpringSessionContext registered, if you override it with thread, the internal hibernate mechanism is going to take over, which doesn't use the spring resource management.

    the Spring doesn't seem to be syncing-up with the Hibernate Session... any thoughts on why that might be?
    Because you basically overridden that behavior.
    Marten Deinum
    Java Consultant / Pragmatist / Open Source Enthousiast / Author


    Pro Spring MVC: With Web Flow
    Conspect

    Have you read the reference guide.
    Use the [ code ] tags, young padawan

  5. #5
    Join Date
    Nov 2008
    Location
    San Francisco, CA
    Posts
    14

    Smile Thanks

    Marten, thanks for taking the time to respond to my questions. Spring is a fantastic framework... part of that is the support that you folks give. Thanks again.

Posting Permissions

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