Page 1 of 2 12 LastLast
Results 1 to 10 of 15

Thread: GenericDAO, Hibernate3, @Transactional

  1. #1

    Default GenericDAO, Hibernate3, @Transactional

    I'm using the GenericDAO pattern per Hibernate's website, along with hibernate3.HibernateTransactionManager, hibernate3.annotation.AnnotationSessionFactoryBean , <tx:annotation-driven/>, sessionFactory.getCurrentSession(), etc.

    The problem is I am getting the somewhat-famous
    Code:
    No Hibernate Session bound to thread
    error. I've determined that if I put @Transactional on the GenericHibernateDAO then it works fine. But the end result (after putting on DEBUG in log4j) is a transaction-per-DAO-method. Which isn't what I want. I'd like something like

    Code:
    public class Test {
    
        //These two from Spring
        private UserDAO userDAO;
        private SiteDAO siteDAO;
    
       @Transactional
       public void doSomething() {
            User u = userDAO.findById(1, false);
            siteDAO.addUserToSite(u, 10);
       }
    }
    and have doSomething() use the same Session for both DAO methods. Is this possible?

  2. #2
    Join Date
    Sep 2006
    Location
    UK
    Posts
    8,424

    Default

    That is completely possible. Is it possible to see the code, configuration and the stacktrace you were getting?
    Barracuda Networks SSL VPN Lead Developer
    http://pramatr.wordpress.com
    http://twitter.com/karldmoore
    http://www.linkedin.com/in/karldmoore
    Any postings are my own opinion, and should not be attributed to my employer or clients.

  3. #3

    Default

    GenericDAO
    Code:
    package com.mycompany.commons.data.dao.support;
    
    import java.io.Serializable;
    import java.util.List;
    
    public interface GenericDAO<T, Id extends Serializable> {
    	public T findById(Id id, boolean lock);
    	public List<T> findAll();
    	public void save(T t);
    	public void update(T t);
    	public void saveOrUpdate(T t);
    	public void deleteById(Id id);
    	public void deleteAll();
    	public Integer count();
    }
    GenericDAOHibernateImpl
    Code:
    package com.mycompany.commons.data.dao.support;
    
    import java.io.Serializable;
    import java.lang.reflect.ParameterizedType;
    import java.util.List;
    
    import org.hibernate.Criteria;
    import org.hibernate.LockMode;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.criterion.Criterion;
    import org.springframework.transaction.annotation.Transactional;
    
    //Must put this here or get "No Hibernate Session bound to thread"
    @Transactional
    public abstract class GenericDAOHibernateImpl<T, Id extends Serializable> implements GenericDAO<T, Id>{
    	private Class<T> persistentClass;
    
    	//IoC properties
    	private SessionFactory sf;
    
    	@SuppressWarnings("unchecked")
    	public GenericDAOHibernateImpl() {
    		this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
                    .getGenericSuperclass()).getActualTypeArguments()[0];
    	}
    
    	@SuppressWarnings("unchecked")
    	public T findById(Id id, boolean lock) {
    		T result;
    		if (lock) { 
    			result = (T) getSession().load(getPersistentClass(), id, LockMode.UPGRADE);
    		}
    		else {
    			result = (T) getSession().load(getPersistentClass(), id);
    		}
    		return result;
    	}
    	
    	public List<T> findAll() {
    		return findByCriteria();
    	}
    		
    	public void save(T t) {
    		getSession().save(t);
    	}
    	
    	public void update(T t) {
    		getSession().update(t);
    	}
    	
    	public void saveOrUpdate(T t) {
    		getSession().saveOrUpdate(t);
    	}
    	
    	@SuppressWarnings("unchecked")
    	protected List<T> findByCriteria(Criterion... criterion) {
    		Criteria crit = getSession().createCriteria(getPersistentClass());
    		for (Criterion c : criterion) {
    			crit.add(c);
    		}
    		return crit.list();
    	}
    	
    	public void deleteById(Id id) {
    		T t = findById(id, false);
    		getSession().delete(t);
    	}
    	
    	public void deleteAll() {
    		getSession().createQuery("delete").executeUpdate();
    	}
    	
    	public Integer count() {
    		return (Integer) getSession().createQuery(
    				"select count(*) from " + getPersistentClass().getName()).uniqueResult();
    	}
    	
    	public Class<T> getPersistentClass() {
    		return persistentClass;
    	}
    	
    	protected Session getSession() {
    		return sf.getCurrentSession();
    	}
    	
    	//IoC setters
    	public void setSessionFactory(SessionFactory sf) {
    		this.sf = sf;
    	}
    		
    }
    SiteDAO
    Code:
    package com.mycompany.commons.data.dao;
    
    import com.mycompany.commons.data.dao.support.GenericDAO;
    import com.mycompany.domain.Site;
    
    public interface SiteDAO extends GenericDAO<Site, Long> {
    	//Nothing to add at the moment
    }
    SiteDAOGenericHibernateImpl
    Code:
    package com.healthdec.commons.data.dao.impl;
    
    import com.mycompany.commons.data.dao.SiteDAO;
    import com.mycompany.commons.data.dao.support.GenericDAOHibernateImpl;
    import com.mycompany.domain.Site;
    
    public class SiteDAOGenericHibernateImpl extends GenericDAOHibernateImpl<Site, Long> implements SiteDAO {
    	//Nothing to add at the moment
    }
    applicationContext.xml
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
    	    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"
        default-autowire="byName">
    
    	<!-- Transaction behavior based on annotations -->
      	<tx:annotation-driven/>
    
    	<!-- Data source -->
    	<bean id="dataSource" 
    			class="org.apache.commons.dbcp.BasicDataSource" 
    			destroy-method="close">
    		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
    		<property name="url" value="jdbc:oracle:thin:@database.mycompany.com1521:DEVELOPMENT"/>
    		<property name="username" value="devuser"/>
    		<property name="password" value="password"/>
    		<property name="maxActive" value="100"/>
    		<property name="maxWait" value="500"/>
    		<property name="validationQuery" value="SELECT SYSDATE FROM DUAL"/>
    	</bean>
    	
    	<!-- Hibernate -->
    	<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    		<property name="annotatedClasses">
    			<list>
    				<value>com.mycompany.domain.Site</value>
    			</list>
    		</property>
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
    				<prop key="hibernate.show_sql">false</prop>
    				<prop key="hibernate.max_fetch_depth">3</prop>
    				<prop key="hibernate.current_session_context_class">thread</prop>
    			</props>
    		</property>
    	</bean>
    	
    	<!-- Transaction -->
    	<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"/>
    	
    	<!-- DAOs -->
    	<bean id="siteDAO" class="com.healthdec.mycompany.data.dao.impl.SiteDAOGenericHibernateImpl"/>
    	
    </beans>

  4. #4
    Join Date
    Sep 2006
    Location
    UK
    Posts
    8,424

    Default

    How about the main method or testCase you are driving all this from?
    Barracuda Networks SSL VPN Lead Developer
    http://pramatr.wordpress.com
    http://twitter.com/karldmoore
    http://www.linkedin.com/in/karldmoore
    Any postings are my own opinion, and should not be attributed to my employer or clients.

  5. #5

    Default

    CommonTestCase
    Code:
    package com.mycompany.commons.data.support;
    
    import org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests;
    
    public class CommonTestCase extends AbstractAnnotationAwareTransactionalTests {
    	
    	public CommonTestCase() {
    		super();
    		setAutowireMode(AUTOWIRE_BY_NAME);
    	}
    		
    	@Override
    	protected String[] getConfigLocations() {
    		return new String[] {
    				"classpath:applicationContext.xml"
    		};
    	}
    	
    }
    TestSiteDAO
    Code:
    package com.mycompany.commons.data.dao;
    
    import junit.framework.Assert;
    
    import com.healthdec.mycompany.data.support.CommonTestCase;
    import com.healthdec.mycompany.Site;
    
    public class TestSiteDAO extends CommonTestCase {	
    	private SiteDAO dao;
    		
            //Tried @Transactional here but it didn't work
    	public void testRead() throws Exception {
    		Site s = dao.findById(1, false);
    		Assert.assertNotNull("Site is null", s);
    	}
    	
    	//Spring injected setters
    	public void setSiteDAO(SiteDAO dao) {
    		this.dao = dao;
    	}
    	
    }

  6. #6
    Join Date
    Sep 2006
    Location
    UK
    Posts
    8,424

    Default

    So when you injected the Test bean instead, it didn't work?
    Code:
    	private Test test;
    		
    	public void testRead() throws Exception {
                             test.doSomething();
    	}
    	
    	public void setTest(Test test) {
    		this.test = test;
    	}
    Barracuda Networks SSL VPN Lead Developer
    http://pramatr.wordpress.com
    http://twitter.com/karldmoore
    http://www.linkedin.com/in/karldmoore
    Any postings are my own opinion, and should not be attributed to my employer or clients.

  7. #7

    Default

    Quote Originally Posted by karldmoore View Post
    So when you injected the Test bean instead, it didn't work?
    Code:
    	private Test test;
    		
    	public void testRead() throws Exception {
                             test.doSomething();
    	}
    	
    	public void setTest(Test test) {
    		this.test = test;
    	}
    That example ^^ did work when @Transactional was put on GenericDAOHibernateImpl. But not when doing this
    Code:
    	private Test test;
    		
            @Transactional
    	public void testRead() throws Exception {
                             test.doSomething();
    	}
    	
    	public void setTest(Test test) {
    		this.test = test;
    	}

  8. #8
    Join Date
    Sep 2006
    Location
    UK
    Posts
    8,424

    Default

    I can't see why it wouldn't work. The configuration doesn't include the Test bean, is it possible to see the version of the classes and files you were using with this. The stacktrace would be useful as well.
    Barracuda Networks SSL VPN Lead Developer
    http://pramatr.wordpress.com
    http://twitter.com/karldmoore
    http://www.linkedin.com/in/karldmoore
    Any postings are my own opinion, and should not be attributed to my employer or clients.

  9. #9

    Default

    All the files I am working with (excluding the domain classes) I have provided. Attempting to run the test results in
    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 $Proxy9.getCurrentSession(Unknown Source)
    	at com.mycompany.commons.data.dao.support.GenericDAOHibernateImpl.getSession(GenericDAOHibernateImpl.java:100)
    	at com.mycompany.commons.data.dao.support.GenericDAOHibernateImpl.findById(GenericDAOHibernateImpl.java:43)
    	at com.mycompany.commons.data.dao.TestSiteDAO.testRead(TestSiteDAO.java:19)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	at java.lang.reflect.Method.invoke(Method.java:585)
    	at junit.framework.TestCase.runTest(TestCase.java:154)
    	at junit.framework.TestCase.runBare(TestCase.java:127)
    	at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:69)
    	at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests.access$001(AbstractAnnotationAwareTransactionalTests.java:47)
    	at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests$1.run(AbstractAnnotationAwareTransactionalTests.java:115)
    	at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests.runTest(AbstractAnnotationAwareTransactionalTests.java:180)
    	at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests.runTestTimed(AbstractAnnotationAwareTransactionalTests.java:153)
    	at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests.runBare(AbstractAnnotationAwareTransactionalTests.java:111)
    	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:130)
    	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)

  10. #10
    Join Date
    Sep 2006
    Location
    UK
    Posts
    8,424

    Default

    I can't see a call to Test.doSomething() in the stacktrace, the only call I see is TestSiteDAO.testRead().
    Barracuda Networks SSL VPN Lead Developer
    http://pramatr.wordpress.com
    http://twitter.com/karldmoore
    http://www.linkedin.com/in/karldmoore
    Any postings are my own opinion, and should not be attributed to my employer or clients.

Posting Permissions

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