当前位置: 首页 > 知识库问答 >
问题:

当@Transactional丢失时,为什么不抛出TransactionRequiredException?

吕新
2023-03-14

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

@Repository
public class UserDao {

    @PersistenceContext
    private EntityManager entityManager;

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

正如预期的那样,实体没有保存,但为什么没有引发异常?持久化的javadoc表示,持久化()应该抛出一个“Transaction必需的异常-如果在容器管理的实体管理器上调用时没有事务,该实体管理器的类型是持久性ContextType。交易”。

调试显示Hibernate有一个打开的会话。这是预期的行为吗?顺便说一句:我在使用EclipseLink时也有同样的行为。

这是我的应用程序上下文。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个答案

梅安平
2023-03-14

javadoc声明,如果在PersistenceContextType.transaction类型的容器管理实体管理器上调用时没有事务,则会出现异常。您的上下文由Spring管理,我认为Spring不是Java EE容器,因此不适用相同的规则,而且上下文可能默认为extended,以便在加入事务之前保存对象。如果要在事务不可用时强制执行异常,请在持久化后调用em.flush()。

越文康
2023-03-14

答案非常清楚和简洁(实际上是您自己发现的):JPA需要一个正在进行的事务来调用EntityManager。持久化(…)。但是,您的代码未设置为在事务内运行。您的配置看起来正常,但在DAO或上面的任何层上都缺少一个@Transactional

由于最初的问题是为什么不抛出异常,我再次查阅了规范,发现在7.9.1中,它显然要求容器在容器管理的持久性上下文中抛出异常。在Spring中运行JPA是一个介于两者之间的场景,因为我们显然不需要JTA之类的,但是可以理解的是,通过注入EntityManager,您假设处于托管环境中。我提交了SPR-11923以改进我们的JPA架构体系支持。

旁注:在使用Spring和JPA时,您可能需要了解Spring Data JPA项目,该项目显著简化了构建数据访问层的html" target="_blank">过程,包括存储库层事务处理的正常默认值(例如,请参阅本指南)。使用它会首先防止你遇到这种情况。

 类似资料:
  • 我创建了一个从HashMap中删除学生的方法。当id为NULL时,它会抛出一个异常。有人知道它为什么不起作用吗? 公共类应用程序{public static void main(String[]args){ }

  • 下面是我的代码。当我运行它时,我在线程“main”java.lang.IndexOutOfBoundsException:Index:3、Size:2中得到异常,而不是我的异常消息。谁能解释一下我做错了什么,为什么会这样?谢谢!

  • 在流处理过程中遇到运行时异常时,流处理是否应该中止?它应该先结束吗?是否应在?异常是按原样重新生成还是已包装?的JavaDoc和java包。util。小溪对此无话可说。 我发现有关Stackoverflow的所有问题似乎都集中在如何从函数接口中包装一个已检查的异常,以使其代码能够编译。事实上,互联网上的博客帖子和类似文章都关注相同的警告。这与我无关。 根据我自己的经验,一旦抛出,序列流的处理就会中

  • 问题内容: 在我的应用程序中,有时会引发以下异常: 很难找到错误,因为在stacktrace中没有列出我的方法。那么,有人知道何时抛出此异常吗?感谢您的任何提示。 问题答案: 您可以在stacktrace中看到错误: 适配器的内容已更改,但ListView没有收到通知。确保不从后台线程修改适配器的内容,而仅从UI线程修改。 您应该调查一个线程,并使其与UI线程同步。 在Android中执行此操作的

  • 问题内容: final Multimap terms = getTerms(bq); for (Term t : terms.keySet()) { Collection C = new HashSet(terms.get(t)); if (!C.isEmpty()) { for (Iterator it = C.iterator(); it.hasNext();) { BooleanClause

  • 问题内容: 我试图将两个’Employee’对象添加到TreeSet中: 但是它抛出一个ClassCastException: 但是,如果我仅将一个对象添加到TreeSet中: 或者,如果我改用HashSet: 那就成功了。为什么会发生异常,我该如何解决? 问题答案: 要么必须实现,或者你需要提供一个比较创建时。 在文档中对此进行了详细说明: 插入排序集中的所有元素都必须实现接口(或被指定的比较器