javax.persistence.TransactionRequiredException:没有可用的事务性 EntityManager

Posted

技术标签:

【中文标题】javax.persistence.TransactionRequiredException:没有可用的事务性 EntityManager【英文标题】:javax.persistence.TransactionRequiredException: No transactional EntityManager available 【发布时间】:2015-01-15 09:37:39 【问题描述】:

从昨天开始,我一直在与这个异常作斗争...我检查了几乎所有内容,搜索了所有链接,但一无所获。

当我从类别服务调用 addCategory 或 removeCategory 时,我总是收到异常 javax.persistence.TransactionRequiredException: No transactional EntityManager available。我附上了所有必要的配置文件。

我想让 Spring 处理事务。

jpaContext.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:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">

    <context:annotation-config />

    <context:component-scan base-package="com.example" />

    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

    <bean id="emf"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="punit" />
        <property name="dataSource" ref="dataSource" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="true"></property>
            </bean>
        </property>

        <property name="jpaPropertyMap">
            <map>
                <entry key="hibernate.dialect" value="org.hibernate.dialect.mysql5InnoDBDialect"></entry>
                <entry key="hibernate.hbm2ddl.auto" value="create-drop"></entry>
                <entry key="hibernate.format_sql" value="true"></entry>
            </map>
        </property>
    </bean>

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

    <tx:annotation-driven transaction-manager="txManager" />

    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url"
            value="jdbc:mysql://localhost:3306/shopify?autoReconnect=true" />
        <property name="username" value="root" />
        <property name="password" value="" />
    </bean>

</beans>

persistence.xml - 在 /META-INF/

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
 http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    version="2.0">

    <persistence-unit name="punit">

    </persistence-unit>

</persistence>

web.xml - 片段,我在其中加载上下文

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        classpath:/jpaContext.xml
        /WEB-INF/security-config.xml
    </param-value>
</context-param>

分类服务

package com.example.service;

import java.util.Collections;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.example.dao.CategoryDao;
import com.example.Category;


@Service
public class CategoryService 

    @Autowired
    @Qualifier("categoryDaoDatabase")
    private CategoryDao categoryDao;

    @Transactional
    public void addCategory(Category category) 
        category.setId(getLastCategoryId() + 1);
        categoryDao.addCategory(category);
    

    @Transactional
    public void removeCategory(Category category) 
        categoryDao.removeCategory(category);
    

    public void setCategoryDao(CategoryDao categoryDao) 
        this.categoryDao = categoryDao;
    


类道

package com.example.dao;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.stereotype.Repository;

import com.example.domain.Category;


@Repository
public class CategoryDaoDatabase implements CategoryDao 

    @PersistenceContext
    private EntityManager entityManager;

    public void addCategory(Category category) 
        entityManager.persist(category);
        entityManager.flush();
    

    public void removeCategory(Category category) 
        entityManager.remove(category);
    

    public void setEntityManager(EntityManager entityManager) 
        this.entityManager = entityManager;
    

Maven 依赖项 - pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.1.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.1.1.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.1.1.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>4.1.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>4.1.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf-spring4</artifactId>
        <version>2.1.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <dependency>
        <groupId>org.hamcrest</groupId>
        <artifactId>hamcrest-all</artifactId>
        <version>1.3</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>4.1.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <version>1.9.5</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-core</artifactId>
        <version>3.2.5.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>3.2.5.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
        <version>3.2.5.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>4.1.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.hsqldb</groupId>
        <artifactId>hsqldb</artifactId>
        <version>2.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>4.3.7.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>4.3.7.Final</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>4.1.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.1.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate.javax.persistence</groupId>
        <artifactId>hibernate-jpa-2.1-api</artifactId>
        <version>1.0.0.Final</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
    </dependency>
</dependencies>

问候, 汤姆

编辑 - 解决方案

正如 M. Deinum 提供的解决方案,问题在于,我提出了

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

<tx:annotation-driven transaction-manager="txManager" />

在 jpaContext.xml 中,我没有加载所有类(它们加载在 shopify-servlet.xml - 我的主要应用程序上下文中)。我将以上几行移到了我的主上下文(shopify-servlet.xml),在那里我进行了组件扫描,它扫描并将所有控制器、服务、存储库加载到主上下文,所以现在@Transactional 工作了:)。

【问题讨论】:

对于初学者来说,不要混合使用 Spring 的 4.1.0、4.1.1 和 4.1.4 的框架版本,不要。如果您有DispatcherServlet,请确保您不再扫描相同的组件,因为这将导致重复的实例与最后一个没有应用 AOP。 我将所有内容设置为 4.1.0,然后设置为 4.1.4,我检查了所有依赖项。它仍然没有工作。这是我的 web.xml:pastebin.com/raw.php?i=k5KKbMms 顺便说一句。我仅在 shopify-servlet(主要上下文)上进行组件扫描 这基本上解释了你的问题。您的组件扫描应该与&lt;tx;annotation-driven /&gt; 在同一个xml 中,否则不会发生任何事情。 AOP 仅适用于同一上下文中的 bean,而不适用于父上下文或子上下文。 另外,在进行组件扫描时,请确保您没有两次检测到组件,因为这将导致相同的错误。根据经验,您的 ContextLoaderListener 应该扫描除网络相关 bean 之外的所有内容(@COntroller 等),而您的 DispatcherServlet 应该只扫描网络相关 bean。 @M.Deinum 它正在工作!非常感谢你!! :) 我会将您的答案添加到我的问题中,因为它们非常有用:)。 【参考方案1】:

正如之前的一篇文章已经指出的那样 - 永远不要混合这样的版本。

您可以用来强制/锁定到一个固定版本,如果您使用简洁的“材料清单”(bom) 资源,您就无需在多个位置指定这样的版本(显然存在丢失某些内容的风险沿着轨道) - 此功能还可以删除依赖关系树中的任何传递依赖关系。

如果您还需要 spring-security,您可以将其锁定到 springframework v4.0.2.RELEASE - 根据 spring doco (http://docs.spring.io/spring-security/site/docs/3.2.5.RELEASE/reference/htmlsingle/#maven-bom) 的说法,这是已完全验证可与 spring-security 3.2.5.RELEASE 一起使用的最大版本。当您使用 bom 时,所有 spring-security 的 springframework v3.2.8.RELEASE 资源将自动被带到 spingframework v4.0.2.RELEASE。

【讨论】:

解决方案在哪里?

以上是关于javax.persistence.TransactionRequiredException:没有可用的事务性 EntityManager的主要内容,如果未能解决你的问题,请参考以下文章