org.hibernate.HibernateException:在我的情况下没有活动事务,save无效

时间:2014-06-30 07:21:45

标签: java spring hibernate

我有GenericService类,它封装了子类的crud方法:

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

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

班级AnswerService延伸GenericService。它会自动装配AnswerDao并声明为@Service@Transactional弹簧组件。

@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扩展了GenericDao,它实现了方法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;
    }

当我在save上调用GenericService方法时,我希望spring为hibernate Session创建事务,但是没有创建事务,我在GenericDaoHibernate.save方法中得到了这个错误:

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

我的服务层的spring配置文件是:

<!-- 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" />

因此,当我不依赖于Spring @Transactional支持并通过org.hibernate.Session开始/提交事务时,一切正常,我没有错误。

为什么spring不为GenericSerice调用的方法提供事务?

BTW,GenericService和AnswerService没有接口。

修改即可。这是HibernateTransactionManager.doGetTransaction方法返回的事务:

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

我也改变了我的服务以使用接口,但它没有帮助。

5 个答案:

答案 0 :(得分:7)

不知道根本原因,但从我的休眠配置中删除以下属性为我解决了这个问题。

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

在此forum

上找到

答案 1 :(得分:1)

getCurrentSession():获得当前会话。

创建一个与上下文会话不同的新会话

openSession():返回:创建的会话。

答案 2 :(得分:0)

我在我的entitymanager中使用org.springframework.orm.jpa.JpaTransactionManager作为我的TransactionManager和Hibernate适配器。

       <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>

我建议更改此配置。

但是如果你不这样做,请尝试在方法doGetTransaction中调试HibernateTransactionManager,看看会发生什么。

答案 3 :(得分:0)

您应该告诉哪些方法或类需要Spring提供跨国支持。 @Transnational Annotation(可以在方法或类级别指定)保证带注释的方法和类的跨国行为,但不保证整个应用程序的跨国行为。

答案 4 :(得分:-1)

也为您的dao方法添加@Transactional注释。