Announcement Announcement Module
Collapse
No announcement yet.
Spring IOC + hibernate Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring IOC + hibernate

    Hi everyone

    I’m a experimenting some problems with the Spring configuration and it would be great if you could help me…

    I’ve been told that in Java applications, it’s a great to use the “Inversion Of Control” pattern... So, I would like to inject the hibernate’s SessionFactory in my DAO objects with the help of Spring IOC (tell me if something is stupid or if I’m wrong).

    I’ve done this and it seems it has been done correctly because I get this error message :

    org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here

    Surfing on the net, I learned the solution would be to provide a “transactional scope” but I don’t want to use the persistence functionalities of Spring, just IOC. Is it a problem ?

    Can you tell me what can I do ?

    Here’s my AppContext.xml
    Code:
    <?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 xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="
           http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
     
     
    	 
    	<!-- Datasource that works in any application server
    	You could easily use J2EE data source instead if this were
    	running inside of a J2EE container.
    	-->
    	<bean id="dataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource" destroy-method="close">
    		<property name="driverClassName">
    			<value>com.mysql.jdbc.Driver</value>
    		</property>
    		<property name="url">
    			<value>jdbc:mysql://localhost/maDB</value>
    		</property>
    		<property name="username">
    			<value>root</value>
    		</property>
    		<property name="password">
    			<value>test</value>
    		</property>
    	</bean>
     
    	<!-- Hibernate SessionFactory -->
    	<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    		<property name="configLocation">
    			<value>classpath:hibernate.cfg.xml</value>
    		</property>
    	</bean>
    	
    	 <bean id="countryDao" class="com.company.countryApp.dao.impl.CountryDaoImpl">
     		<property name="sessionFactory">
     			<ref local="mySessionFactory"/>
     		</property>
     	</bean>

    Thank you

  • #2
    Hello,

    may you post a piece of code that causes this exception?

    Regards,
    Oleksandr

    Comment


    • #3
      of course

      this is caused by this very simple JUnit class.



      Code:
      package com.company.countryApp.junits;
      import org.hibernate.Session;
      import org.springframework.beans.factory.BeanFactory;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      import com.company.countryApp.bo.Country;
      import junit.framework.TestCase;
      
      public class CountryTestUnit extends TestCase {
      
      	private CountryDao myCountryDao;
      	
      	protected void setUp() throws Exception{
      		super.setUp();
      		
      		ApplicationContext appContext = new ClassPathXmlApplicationContext("/applicationContext.xml");
      
      		BeanFactory factory = (BeanFactory) appContext;
      		myCountryDao = (CountryDao) factory.getBean("countryDao");
      		
      	}
      	
      	protected void tearDown() throws Exception{
      		myCountryDao.getSessionFactory().close();
      	}
      	
      	
      	public void testSaveCountry(){
      		Session session = myCountryDao.getSessionFactory().getCurrentSession();
                      session.beginTransaction();
              
                      Country country = new Country();
                      country.setName("USA");
              
                      long idCountry1 = myCountryDao.saveCountry(country);
              
      	        session.getTransaction().commit();
      		
      	        Session session2 = myCountryDao.getSessionFactory().getCurrentSession();
                      session2.beginTransaction();
      		
                      Country country2 = myCountryDao.getCountryById(idCountry1);
                      assertEquals(country.getName(), country2.getName());
              
                      session2.getTransaction().commit();
      	}
      	
      }

      and the DAO class :

      Code:
      package com.company.countryApp.dao.impl;
      
      import java.util.List;
      
      import org.hibernate.Session;
      import org.hibernate.SessionFactory;
      import com.company.countryApp.bo.Country;
      import com.company.countryApp.dao.CountryDao;
      import com.company.countryApp.util.CheckTool;
      
      public class CountryDaoImpl implements CountryDao {
      
      	private SessionFactory sessionFactory;
      	
      	public CountryDaoImpl(){
      		
      	}
      
      	public long saveCountry(Country country) {
      		CheckTool.check(country);
      		Session session = this.sessionFactory.getCurrentSession();
                      session.save(country);
                      return country.getIdCountry();
      	}
      
      	public void updateCountry(Country country) {
      		CheckTool.check(country);	
      		Session session = this.sessionFactory.getCurrentSession();
      		session.update(country);
      	}
      
      	public void refreshCountry(Country country) {
      		CheckTool.check(country);
          	        Session session = this.sessionFactory.getCurrentSession();
          	        session.refresh(country);
      	}
      
      	public void deleteCountry(Country country) {
      		CheckTool.check(country);
          	        Session session = this.sessionFactory.getCurrentSession();
          	        session.delete(country);
      	}
      
      	public Country getCountryById(long id) {
      		CheckTool.checkId(id);
          	        Session session = this.sessionFactory.getCurrentSession();
          	        Countrycountry= (Country) session.load(Country.class, id);
          	        return country;
      	}
      
      
      	public void setSessionFactory(SessionFactory sessionFactory) {
      		this.sessionFactory = sessionFactory;
      	}
      
      	public SessionFactory getSessionFactory() {
      		return sessionFactory;
      	}
      
      }
      Last edited by sixtiesman; Mar 26th, 2007, 10:25 AM.

      Comment


      • #4
        I don't know exactly what is wrong but, I am using HiberanteTemplate instead of working directly on the SessionFactory. It is working nice and I don't have a transaction manager declared(yet!).

        Regardless, you can take several advantages os spring's hibernate support using this approach.

        Check it out: http://static.springframework.org/sp...rnate-template

        Comment


        • #5
          Also,
          Read this chapter on Testing: http://static.springframework.org/sp...ing-fixture-di

          Using Spring's testing support allow you to dependency inject objects in your test class without all the "beanFactory.getBean()" stuff.

          Comment


          • #6
            It's always useful to see the full stacktrace. I would agree working with HibernateTemplate is an easier option and IMHO is nicer to work with. I think transactions should make your problem go away. If you are writing unit tests, I would have a look at the Spring test classes. These actually provide a transaction for you.
            http://www.springframework.org/docs/...tml#testing-tx
            http://www.springframework.org/docs/...ansaction.html

            Comment


            • #7
              thank you for your very good answers

              I'll have a look at these tomorrow. Very interesting.

              karldmoore : what is IMHO ?

              Comment


              • #8
                Hi sixtiesman

                The issue you describe has nothing to do with Spring... your usage of Spring is fine as is.

                The issue is with Hibernate, and your usage of it. You need to read the following section of the Hibernate Reference Manual to understand the semantics of the getCurrentSession() method.

                http://www.hibernate.org/hib_docs/v3...urrent-session

                Once you have configured an appropriate CurrentSessionContext implementation, your code will at least 'work' (in that the Exception that is being thrown will no longer be thrown).

                Cheers
                Rick

                Comment


                • #9
                  Hi sixtiesman

                  The issue you describe has nothing to do with Spring... your usage of Spring is fine as is.

                  The issue is with Hibernate, and your usage of it. You need to read the following section of the Hibernate Reference Manual to understand the semantics of the getCurrentSession() method.

                  http://www.hibernate.org/hib_docs/v3...urrent-session

                  Once you have configured an appropriate CurrentSessionContext implementation, your code will at least 'work' (in that the Exception that is being thrown will no longer be thrown).

                  Cheers
                  Rick

                  Comment


                  • #10
                    Originally posted by sixtiesman View Post
                    karldmoore : what is IMHO ?
                    , In My Humble Opinion.

                    Comment


                    • #11
                      karldmoore : EMIDKI (Excuse me, I didn't know it)

                      Rick Evans : hi Rick, I didn't know it but as you can see in my hibernate.cfg.xml file, I've defined a "current_session_context_class" but the problem still remains. Is it correct ?

                      The hibernate.cfg.xml file :
                      Code:
                      <?xml version='1.0' encoding='utf-8'?>
                      <!DOCTYPE hibernate-configuration PUBLIC
                              "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
                              "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
                      <hibernate-configuration>
                      
                          <session-factory>
                              <!--MySQL JDBC Driver connection -->
                              <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
                              <property name="connection.url">jdbc:mysql://localhost/maDB</property>
                              <property name="connection.username">root</property>
                              <property name="connection.password">test</property>
                              <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
                      
                              <!-- JDBC connection pool (use the built-in) -->
                              <property name="connection.pool_size">1</property>
                      
                              <!-- Enable Hibernate's automatic session context management -->
                              <property name="current_session_context_class">org.hibernate.context.JTASessionContext</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="com/company/countryApp/bo/Country.hbm.xml"/>
                      
                          </session-factory>
                      </hibernate-configuration>
                      The full stack trace :
                      Code:
                      org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
                      	at org.springframework.orm.hibernate3.AbstractSessionFactoryBean$TransactionAwareInvocationHandler.invoke(AbstractSessionFactoryBean.java:299)
                      	at $Proxy0.getCurrentSession(Unknown Source)
                      	at com.company.countryApp.junits.CountryTestUnit.testSaveCountry(CountryTestUnit.java:32)
                      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                      	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
                      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
                      	at java.lang.reflect.Method.invoke(Unknown Source)
                      	at junit.framework.TestCase.runTest(TestCase.java:154)
                      	at junit.framework.TestCase.runBare(TestCase.java:127)
                      	at junit.framework.TestResult$1.protect(TestResult.java:106)
                      	at junit.framework.TestResult.runProtected(TestResult.java:124)
                      	at junit.framework.TestResult.run(TestResult.java:109)
                      	at junit.framework.TestCase.run(TestCase.java:118)
                      	at junit.framework.TestSuite.runTest(TestSuite.java:208)
                      	at junit.framework.TestSuite.run(TestSuite.java:203)
                      	at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:128)
                      	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
                      	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
                      	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
                      	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
                      	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
                      However, I'll follow your recommendations for the use of HibernateTemplate instead of working directly with the SessionFactory…

                      Comment


                      • #12
                        sixtiesman, i'm having the same problem trying to use plain hibernate3 api in my daos, and found no solution yet. i raised this question again at

                        http://forum.springframework.org/showthread.php?t=42297

                        i think it's important to continue this issue because i've seen various references to this same problem, which leads me to think if the spring documentation might be missing something.

                        Comment


                        • #13
                          hi dazen6

                          I'm not a J2EE expert but I never managed to implement the "plain hibernate3 api" in my DAO's. I've not been helped (I'm a student and I did it during a traning period) and I gave up this idea after hours !

                          The problem only disappeared when I used the "HibernateTemplate" class instead of the "SessionFactory" class provided by Hibernate and I handled the transactions the declarative way.

                          I really advise you to do this but I really would be curious to know how we can solve this an other way.

                          good luck dazen6 !

                          Comment

                          Working...
                          X