为什么在缺少@Transactional时没有抛出TransactionRequiredException?

时间:2014-06-25 14:28:06

标签: java spring hibernate jpa transactions

我已经将Hibernate作为持久性提供程序进行了Spring / JPA配置。但是,当我在没有打开事务的情况下对以下DAO代码调用save()时,我不明白为什么没有抛出TransactionRequiredException(在DAO /服务中没有@Transactional):

@Repository
public class UserDao {

    @PersistenceContext
    private EntityManager entityManager;

    public void save(User user) {
        entityManager.persist(user);
    }
}

正如预期的那样,实体没有保存,但为什么没有抛出异常? javadoc for persist表示persist()应抛出" TransactionRequiredException - 如果在容器管理的实体管理器上调用时没有事务,那么PersistenceContextType.TRANSACTION"。

调试显示Hibernate具有开放会话。这是预期的行为吗?顺便说一句:使用EclipseLink时我得到了同样的行为。

这是我的applicationContext.xml:

<?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:context="http://www.springframework.org/schema/context"   xmlns:jee="http://www.springframework.org/schema/jee" xmlns:lang="http://www.springframework.org/schema/lang" xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

<context:component-scan base-package="com.foo.bar" />
<context:annotation-config />
<tx:annotation-driven />

<!-- Configure jdbc.properties -->
<bean id="propertyConfigurer"
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
    p:location="/WEB-INF/jdbc.properties" />

<!-- Data Source configuration -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close" p:driverClassName="${jdbc.driverClassName}"
    p:url="${jdbc.databaseurl}" p:username="${jdbc.username}" p:password="${jdbc.password}" />

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="database" value="HSQL" />
            <property name="showSql" value="true" />
        </bean>
    </property>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.hbm2ddl.auto">create</prop>
        </props>
    </property>
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<bean id="persistenceExceptionTranslationPostProcessor"
    class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

修改 Hibernate版本(来自pom.xml)

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>4.3.5.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>4.3.5.Final</version>
    <exclusions>
        <exclusion>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
        </exclusion>
        <exclusion>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.hibernate.javax.persistence</groupId>
    <artifactId>hibernate-jpa-2.0-api</artifactId>
    <version>1.0.1.Final</version>
</dependency>

2 个答案:

答案 0 :(得分:2)

答案非常清晰简洁(您实际上是自己发现的):JPA要求正在进行调用EntityManager.persist(…)的事务。但是,您的代码未设置为在事务内运行。您的配置看起来很清晰,但您在DAO或上面的任何一层上都错过了@Transactional

由于最初的问题是为什么不抛出异常,我再次查看规范并发现在7.9.1中它明显要求容器将该异常抛出到容器管理的持久化上下文中。在Spring中运行JPA是一个介于两者之间的场景,因为我们显然不需要JTA等,但可以理解的是,注入EntityManager您认为是在托管中环境。我提交了SPR-11923来改进我们的JPA基础架构支持。

侧面跟踪:使用Spring和JPA时,您可能需要查看Spring Data JPA project,它可以显着简化构建数据访问层的过程,包括存储库层上事务处理的合理默认值(例如,请参阅此guide。使用它会阻止您首先遇到这种情况。

答案 1 :(得分:0)

javadoc指出,如果在容器管理的实体管理器上调用PersistenceContextType.TRANSACTION时没有事务,则会出现异常“ 您的上下文由Spring管理,我认为它不是Java EE容器,因此相同的规则不适用,并且上下文可能默认为扩展,以便在加入事务之前保留对象。如果要在事务不可用时强制执行异常,请在保留后调用em.flush()。