简体   繁体   English

Spring JPA 没有正在进行的交易

[英]Spring JPA no transaction is in progress

I am new to Spring and JPA, wasted 5 days and no result with searching inte.net.我是 Spring 和 JPA 的新手,浪费了 5 天时间,在 inte.net 上搜索没有结果。 I want to save object to SQL SERVER, connection is correct but when I write.flush() I get the exception我想将 object 保存到 SQL SERVER,连接是正确的,但是当我写 .flush() 时出现异常

nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress嵌套异常是 javax.persistence.TransactionRequiredException:没有事务正在进行

This is my jpaContext.xml这是我的 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"
xsi:schemaLocation="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-3.1.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">

<context:annotation-config />
<context:component-scan base-package="com.misha.service"/>
<context:component-scan base-package="com.misha.repository"/>
<context:component-scan base-package="com.misha.model"/>

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

<bean id="myEntityManager"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" value="com.misha.model"/>
    <property name="persistenceUnitName" value="test" /> 
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
    </property>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.format_sql">true</prop>
            <prop key="hibernate.hbm2ddl.auto">create</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
        </props>
    </property>
</bean>
<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver" />
    <property name="url"
        value="jdbc:jtds:sqlserver://127.0.0.1;instance=SQLEXPRESS;DatabaseName=misha" />
    <property name="username" value="sa" />
    <property name="password" value="root" />
</bean>

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

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

</beans>

This is my persistence.xml file:这是我的 persistence.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="test" >
        <class>com.misha.model.Table1</class>
    </persistence-unit> 
</persistence>

This is my Service implementation:这是我的服务实现:

@Service("manService")
public class SaveManImpl implements SaveMan {
//  
    @Autowired
    private ManRepositoryImpl manRepo;


    @Transactional
    public Table1 save(Table1 table) {
        manRepo.save(table);
        return null;
    }

}

And finally my Repository implementation:最后是我的存储库实现:

@Repository("manRepository")
public class ManRepositoryImpl implements ManRepository {

    @PersistenceContext
    private EntityManager em;   

    public Table1 save(Table1 table){
        em.persist(table);
        em.flush();
        return table;
    }
}

From the exception, Spring cant see @Transactional annotation, am I right?从异常来看,Spring 看不到@Transactional 注解,对吗? I tried to put the annotation above repository save method, no result, after this above Service save method, the same here.我试着把注解放在repository save方法上面,没有结果,在这个上面的Service save方法之后,这里也是一样的。 Thanks in advance提前致谢

在此处输入图像描述

I call the save method in my Controller我在我的 Controller 中调用了保存方法

    package com.misha.controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;

import com.misha.model.Table1;
import com.misha.service.SaveMan;

@Controller
public class ManController {
    @Autowired 
    SaveMan saveMan; // this is service interface


    @RequestMapping(value="/test1")
    public String saveMan(){
        Table1 tab = new Table1();
        tab.setName("name");
        saveMan.save(tab);          
        return "saveMan";
    }   
}

Error stack:错误堆栈:

SEVERE: Servlet.service() for servlet [fitTrackerServlet] in context with path [/test] threw exception [Request processing failed; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress] with root cause
javax.persistence.TransactionRequiredException: no transaction is in progress
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.checkTransactionNeeded(AbstractEntityManagerImpl.java:1171)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1332)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
    at com.sun.proxy.$Proxy20.flush(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
    at com.sun.proxy.$Proxy20.flush(Unknown Source)
    at com.misha.repository.ManRepositoryImpl.save(ManRepositoryImpl.java:21)
    at com.misha.service.SaveManImpl.save(SaveManImpl.java:19)
    at com.misha.controllers.ManController.saveMan(ManController.java:21)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:175)
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:421)
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:409)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:774)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:618)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:537)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1085)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658)
    at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1556)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1513)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Unknown Source)

Spring configuration file Spring 配置文件

<?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"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.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-3.1.xsd">

    <mvc:annotation-driven />
    <!--<mvc:resources location="pdfs" mapping="/pdfs/**" />
    <mvc:resources location="/resources" mapping="/resources/**"/> -->
    <context:component-scan base-package="com.misha.controllers"></context:component-scan>
    <context:component-scan base-package="com.misha.repository" />
    <context:component-scan base-package="com.misha.service" />

    <context:annotation-config/>

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


<bean id="contentNegotiatingViewResolver"
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
  <property name="order" value="1" />
  <property name="mediaTypes">
    <map>
      <entry key="json" value="application/json" />
      <entry key="xml" value="application/xml" />
      <entry key="request" value="text/html" />
    </map>
  </property>
  <property name="favorPathExtension" value="false" />
  <property name="favorParameter" value="true" />
  <property name="defaultViews">
    <list>

    </list>
  </property>
</bean>

<bean class="org.springframework.context.support.ResourceBundleMessageSource"  >
    <property name="basename" value="WEB-INF/messages"></property>

</bean>


</beans>

You have two Spring contexts: 你有两个Spring上下文:

  1. the main one, configured by jpaContext.xml, where beans from the service and repository packages are scanned, and proxied by a transactional interceptor. 主要的一个,由jpaContext.xml配置,其中来自服务和存储库包的bean被扫描,并由事务拦截器代理。

  2. the mvc one, configured by the other xml file (you didn't name it) whose role is to describe the MVC part of the application, ie define and configure for example the controller beans, the view resolver, etc. This context is a child of the main one. mvc one,由另一个xml文件(你没有命名)配置,其作用是描述应用程序的MVC部分,即定义和配置例如控制器bean,视图解析器等。这个上下文是一个主要的孩子。

The problem is that you also scan the service and repository packages in this child context. 问题是您还在此子上下文中扫描服务和存储库包。 You thus end up with two instances of each service and repository: 因此,您最终得到了每个服务和存储库的两个实例:

  • one in the main context, which is transactional 一个在主要上下文中,这是事务性的
  • one in the child context, which is not (since the child context doesn't care about transaction management) 子上下文中的一个,不是(因为子上下文不关心事务管理)

The controller is thus injected with a service coming from the same context as the controller: the not transactional one. 因此,控制器注入来自与控制器相同的上下文的服务:非事务性的服务。

To confirm that, you could add traces in the constructor of the beans and see how many times they are instantiated. 要确认这一点,您可以在bean的构造函数中添加跟踪,并查看它们实例化的次数。

And to avoid the problem, there are two solutions: 为了避免这个问题,有两种解决方案:

  • avoid scanning the repository and service packages in the mvc context: this context should only care about mvc-related beans. 避免在mvc上下文中扫描存储库和服务包:此上下文应该只关心与mvc相关的bean。 When Spring injects a service in a controller, it would thus not find the service in the mvc context, and thus look it up, and find it in the main context. 当Spring在控制器中注入服务时,它将不会在mvc上下文中找到服务,因此查找它,并在主上下文中找到它。 The transactional service would thus be injected. 因此将注入交易服务。
  • use a single context: the one of the servlet, where all the beans in the application would be defined. 使用单个上下文:servlet之一,其中将定义应用程序中的所有bean。

You should introduce your entity manager to your transaction manager, so that when you annotate your function with @Transactional it loads instances from the pool 您应该将您的实体管理器介绍给您的事务管理器,这样当您使用@Transactional注释您的函数时,它会从池中加载实例

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="myEmf" />
</bean>
<tx:annotation-driven />

HTH! HTH!

To make the story short, try adding @Transactional at the very beginning of your method. @Transactional故事,请尝试在方法的最开头添加@Transactional That was an issue in my case. 这是我的问题。

I had the same issue, in my case, I was using a library with the DAOs anotated with @Transactional , but it was not org.springframework.transaction.annotation.Transactional from Spring, it was javax.transaction.Transactional , wich can not be named, so you can't specify a TransactionManager:我遇到了同样的问题,在我的情况下,我使用的是带有带有@Transactional注释的 DAO 的库,但它不是 Spring 的org.springframework.transaction.annotation.Transactional ,它是javax.transaction.Transactional ,不能被命名,所以你不能指定一个 TransactionManager:

@Transactional("transactionManagerName")
public class DaoImpl implements Dao {...}

Get it's transaction manager like this one, from a config file in my case:在我的例子中,从配置文件中获取它的事务管理器:

    @Bean("transactionManagerName")
    public PlatformTransactionManager transactionManager() 
    throws SQLException, NamingException {
        final HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(this.sessionFactory().getObject());
        return transactionManager;
    }

use in Hibernate properties在 Hibernate 属性中使用

properties.put("hibernate.allow_update_outside_transaction", "true"); properties.put("hibernate.allow_update_outside_transaction", "true");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM