6

I have GenericService class which encapsulates crud methods for subclasses:

public abstract class GenericService<D extends GenericDao<T, I>, T extends DomainObject<I>, I> {

    public I save(T t) {
        return getDao().save(t);
    }
...........................
}

Class AnswerService extends GenericService. It autowires AnswerDao and declares itself as @Service and @Transactional spring component.

@Service
@Transactional(propagation = Propagation.REQUIRED)
public class AnswerService extends GenericService<AnswerDao, Answer, Long> {

    @Autowired
    private AnswerDao answerDao;

    @Override
    public void setDao(AnswerDao d) {
        this.answerDao = d;
    }

    @Override
    public AnswerDao getDao() {
        return answerDao;
    }
................................
}

AnswerDao extends GenericDao which implements method save.

public abstract class GenericDaoHibernate<T extends DomainObject<I>, I extends Serializable> implements GenericDao<T, I> {

    private Class<? extends T> entityClass;
    private SessionFactory sessionFactory;

    public GenericDaoHibernate(Class<? extends T> entityClass) {
        this.entityClass = entityClass;
    }

    public GenericDaoHibernate() {
    }

    @Autowired
    private void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
        Assertor.assertNotNull(sessionFactory);
    }

    public Session currentSession() {
        return getSessionFactory().getCurrentSession();
    }

    @SuppressWarnings("unchecked")
    @Override
    public I save(T entity) {
        // Transaction transaction = currentSession().beginTransaction();
        I id = (I) currentSession().save(entity);
        // transaction.commit();
        return id;
    }

When I call save method on GenericService I expect spring to create transaction for hibernate Session, but transaction is not created and I get this error right in GenericDaoHibernate.save method:

org.hibernate.HibernateException: save is not valid without active transaction

My spring config file for service layer is:

<!-- Hibernate 4 SessionFactory -->
        <bean id="sessionFactory"
            class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"
            p:dataSource-ref="dataSource" p:packagesToScan="com.javahelp.domain.impl">
            <property name="configLocations">
                <array>
                    <value>classpath:META-INF/hibernate/hibernate.cfg.xml</value>
                </array>
            </property>
        </bean>
        <!-- A transaction manager for working with Hibernate session methods. 
            Without this transaction manager none method of hibernate session works -->
        <bean id="transactionManager"
            class="org.springframework.orm.hibernate4.HibernateTransactionManager">
            <property name="sessionFactory" ref="sessionFactory" />
        </bean>

    <!-- enable scanning for @Transactional annotation -->
        <tx:annotation-driven transaction-manager="transactionManager" />

        <!-- autodetect all spring @Service beans in package com.javahelp.service 
            (service layer) -->
        <context:component-scan base-package="com.javahelp.service" />

So when I don't rely on spring @Transactional support and begin/commit transaction by org.hibernate.Session then all is ok and I have no error.

Why spring doesn't provide transaction for methods called on GenericSerice?

BTW, GenericService and AnswerService have no interfaces.

EDIT. This is transaction that is returned by HibernateTransactionManager.doGetTransaction method:

txObject    HibernateTransactionManager$HibernateTransactionObject  (id=190)    
    connectionHolder    null    
    newSession  false   
    newSessionHolder    false   
    previousIsolationLevel  null    
    savepointAllowed    false   
    sessionHolder   null    

I also changed my services to use interfaces but it didn't help.

Volodymyr Levytskyi
  • 3,364
  • 9
  • 46
  • 83

5 Answers5

7

Don't know the root cause, but removing the below property from my hibernate configuration solved the problem for me.

<prop key="hibernate.current_session_context_class">thread</prop>

Found on this forum

jjr4826
  • 194
  • 3
  • 12
  • worth looking at this post http://stackoverflow.com/questions/18832889/spring-transactions-and-hibernate-current-session-context-class as it is explained in more detail. – sarabdeep singh Mar 17 '15 at 17:43
1

getCurrentSession() : Obtains the current session.

Creates a new session, different from the contextual session

openSession() : Returns: The created session.

iCrazybest
  • 2,935
  • 2
  • 24
  • 24
0

I´, using org.springframework.orm.jpa.JpaTransactionManager for my TransactionManager and Hibernate adapter in my entitymanager.

       <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
    <property name="dataSource" ref="dataSource"/>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
    </property>
    <property name="packagesToScan" value="domain"/>
    <property name="jpaPropertyMap">
        <map>
            <entry key="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
            <entry key="javax.persistence.jdbc.driver" value="org.mariadb.jdbc.Driver" />
            <entry key="hibernate.show_sql" value="false" />
            <entry key="hibernate.multiTenancy" value="SCHEMA" />
            <entry key="hibernate.multi_tenant_connection_provider" value-ref="mySQLMultiTenantConnectionProvider" />
            <entry key="hibernate.tenant_identifier_resolver" value-ref="tenantIdentifierResolver" />
        </map>
    </property>
</bean>

I suggest to changes to this configuration.

But if you dont, try to debug in HibernateTransactionManager in the method doGetTransaction ans see what´s going on.

paul
  • 12,873
  • 23
  • 91
  • 153
0

You should tell about which methods or classes that needs transnational support from Spring . @Transnational Annotation (can be specified on method or class level) guarantees transnational behavior for the annotated methods and classes but not to the entire application.

Bhargav Kumar R
  • 2,190
  • 3
  • 22
  • 38
-1

Add @Transactional annotations to your dao methods as well.

Stefan
  • 12,108
  • 5
  • 47
  • 66