Spring - 没有可用于当前线程的实际事务的EntityManager - 无法可靠地处理'persist'调用

Mic*_*Bil 107 java spring web-applications spring-mvc

尝试调用"persist"方法将实体模型保存到Spring MVC Web应用程序中的数据库时,我收到此错误.无法在互联网上找到任何与此特定错误相关的帖子或页面.似乎EntityManagerFactory bean出了问题,但我对Spring编程还是比较新的,所以对我来说似乎所有内容都已经初始化很好并且根据web中的各种教程文章.

调度员servlet.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:mvc="http://www.springframework.org/schema/mvc"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
 http://www.springframework.org/schema/mvc 
 http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
 http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
 http://www.springframework.org/schema/context 
  http://www.springframework.org/schema/context/spring-context-4.0.xsd
  http://www.springframework.org/schema/jdbc
  http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
  http://www.springframework.org/schema/data/jpa
  http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
  http://www.springframework.org/schema/data/repository
  http://www.springframework.org/schema/data/repository/spring-repository-1.5.xsd
  http://www.springframework.org/schema/jee
  http://www.springframework.org/schema/jee/spring-jee-3.2.xsd">

    <context:component-scan base-package="wymysl.Controllers" />
    <jpa:repositories base-package="wymysl.repositories"/> 
    <context:component-scan base-package="wymysl.beans" /> 
    <context:component-scan base-package="wymysl.Validators" /> 
    <bean
     class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
     <bean class="org.springframework.orm.hibernate4.HibernateExceptionTranslator"/>

     <bean id="passwordValidator" class="wymysl.Validators.PasswordValidator"></bean>

     <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">

        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
        <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
        <property name="username" value="system" />
        <property name="password" value="polskabieda1" />
    </bean>

 <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceXmlLocation" value="classpath:./META-INF/persistence.xml" />
    <property name="dataSource" ref="dataSource" />

    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="databasePlatform" value="org.hibernate.dialect.H2Dialect" />
            <property name="showSql" value="true" />
            <property name="generateDdl" value="false" />
        </bean>
    </property>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.max_fetch_depth">3</prop>
            <prop key="hibernate.jdbc.fetch_size">50</prop>
            <prop key="hibernate.jdbc.batch_size">10</prop>
        </props>
    </property>
</bean>

    <mvc:annotation-driven />

    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basename" value="classpath:messages" />
</bean>

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


    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix">
        <value>/WEB-INF/jsp/</value>
    </property>
    <property name="suffix">
        <value>.jsp</value>
    </property>
</bean>

    <mvc:resources mapping="/resources/**" location="/resources/" />
    <mvc:resources mapping="/resources/*" location="/resources/css/"  
    cache-period="31556926"/>



</beans>
Run Code Online (Sandbox Code Playgroud)

RegisterController.java

@Controller
public class RegisterController {

    @PersistenceContext
    EntityManager entityManager;

    @Autowired
    PasswordValidator passwordValidator;

    @InitBinder
    private void initBinder(WebDataBinder binder) {
        binder.setValidator(passwordValidator);
    }

    @RequestMapping(value = "/addUser", method = RequestMethod.GET)
    public String register(Person person) {


        return "register";

    }

    @RequestMapping(value = "/addUser", method = RequestMethod.POST)
    public String register(@ModelAttribute("person") @Valid @Validated Person person, BindingResult result) {
        if(result.hasErrors()) {
            return "register";
        } else {
            entityManager.persist(person);
            return "index";

        }




    }
Run Code Online (Sandbox Code Playgroud)

mlg*_*mlg 210

我有同样的问题,我注释了方法@Transactional,它的工作原理.

更新:默认情况下检查弹出文档,PersistenceContext的类型为Transaction,这就是为什么该方法必须是事务性的(http://docs.spring.io/spring/docs/current/spring-framework-reference/ html/orm.html):

@PersistenceContext注释具有可选的属性类型,默认为PersistenceContextType.TRANSACTION.此默认值是接收共享EntityManager代理所需的内容.替代方案PersistenceContextType.EXTENDED是一个完全不同的事情:这会产生一个所谓的扩展EntityManager,它不是线程安全的,因此不能在并发访问的组件中使用,例如Spring管理的单例bean.扩展的EntityManagers仅应用于有状态组件,例如驻留在会话中,EntityManager的生命周期不依赖于当前事务,而是完全取决于应用程序.

  • 如果没有`@Transactional` annotion的方法在同一个类文件中调用带有@@ Transactional`注释的方法,那么你也会被这个错误所震撼(这就是我所面对的). (58认同)
  • 值得一提的另一件事是,这个注释应该用于公共方法,因为它不起作用. (8认同)
  • 我使用`@Transactional`注释了服务类,它也有效.不确定这是否是正确的方法,但它似乎工作正常...... (5认同)
  • 请记住,@ Transaction仅适用于公共方法. (5认同)
  • 仅供参考,这需要javax.transaction.Transactional注释(不是Spring注释)。 (2认同)

小智 67

尝试在spring数据存储库中使用deleteBy自定义方法时出现此异常.该操作是从JUnit测试类尝试的.

@Transactional在JUnit类级别使用注释时不会发生异常.

  • 我处于相同的情况,而不是注释测试类我注释了服务方法,所以即使它不是测试它也会逐渐减少. (7认同)
  • 我在存储库方法上使用了“@Trasactional”,因为它是我实际与数据库交互的地方并且它工作正常。 (5认同)
  • 我在尝试“deleteBy”时遇到了这个问题。我将方法更改为“删除”并将整个对象作为参数传递。 (2认同)
  • 在愚弄查德·德比的教程时遇到了这个问题。他教导说,默认情况下,jpa 在服务级别具有 @transactional,因此我们不需要在此处添加它。但在删除的情况下,我们实际上需要在使用entityManager.remove(object)时 (2认同)

小智 22

您需要将 @Transactional 添加到您的方法中

  • 通过额外的支持信息可以改进您的答案。请[编辑]添加更多详细信息,例如引文或文档,以便其他人可以确认您的答案是正确的。您可以[在帮助中心](/help/how-to-answer)找到有关如何写出好的答案的更多信息。 (7认同)

小智 16

这个错误让我厌倦了三天,我遇到的情况产生了同样的错误.按照我能找到的所有建议,我玩配置但无济于事.

最终我发现它,不同之处在于,我正在执行的服务包含在一个普通的jar中,问题结果是AspectJ没有对Service实例化进行同样的处理.实际上,代理只是调用底层方法而没有在方法调用之前执行所有正常的Spring魔术.

最后,根据示例放置在服务上的@Scope注释解决了问题:

@Service
@Scope(proxyMode = ScopedProxyMode.INTERFACES)
@Transactional
public class CoreServiceImpl implements CoreService {
    @PersistenceContext
    protected EntityManager entityManager;

    @Override
    public final <T extends AbstractEntity> int deleteAll(Class<T> clazz) {
        CriteriaDelete<T> criteriaDelete = entityManager.getCriteriaBuilder().createCriteriaDelete(clazz);
        criteriaDelete.from(clazz);
        return entityManager.createQuery(criteriaDelete).executeUpdate();
    }

}
Run Code Online (Sandbox Code Playgroud)

我发布的方法是删除方法,但注释以相同的方式影响所有持久性方法.

我希望这篇文章可以帮助那些在从jar加载服务时遇到同样问题的人


小智 15

boardRepo.deleteByBoardId(id);

面临同样的问题。GOT javax.persistence.TransactionRequiredException: 没有 EntityManager 与当前线程可用的实际事务

我通过在控制器/服务上方添加@Transactional注释来解决它。


Leo*_*Leo 10

org.springframework.transaction.annotation.Transactional在测试类的类级别添加注释为我解决了这个问题。

  • 请注意,这将为类外部的每个方法调用打开一个读写事务。这可能不是您想要的,尤其是在高负载情况下。您可能需要考虑将注释添加到有问题的方法而不是类中。 (2认同)

Ser*_*fel 9

我有同样的错误,因为我从XML转换为java配置.

关键是,我没有<tx:annotation-driven/>像Stone Feng所说的那样迁移标签.

所以我刚刚@EnableTransactionManagement按照@Configuration Class中的Spring设置注释驱动事务的建议添加, 现在它可以工作了


小智 8

从同一组件中的非事务方法访问已经事务注释的方法时,我遇到了同样的错误:

Before:
    @Component
    public class MarketObserver {
        @PersistenceContext(unitName = "maindb")
        private EntityManager em;

        @Transactional(value = "txMain", propagation = Propagation.REQUIRES_NEW)
        public void executeQuery() {
          em.persist(....);
        }


        @Async
        public void startObserving() {
          executeQuery(); //<-- Wrong
        }
    }

    //In another bean:
     marketObserver.startObserving();
Run Code Online (Sandbox Code Playgroud)

我通过在自引用组件上调用executeQuery() 修复了错误:

Fixed version:
    @Component
    public class MarketObserver {
        @PersistenceContext(unitName = "maindb")
        private EntityManager em;

        @Autowired
        private GenericApplicationContext context;

        @Transactional(value = "txMain", propagation = Propagation.REQUIRES_NEW)
        public void executeQuery() {
          em.persist(....);
        }


        @Async
        public void startObserving() {
          context.getBean(MarketObserver.class).executeQuery(); //<-- Works
        }
    }
Run Code Online (Sandbox Code Playgroud)


小智 5

我遇到了同样的问题,我加入tx:annotation-driven进来applicationContext.xml并成功了。