Spring JPA 没有正在进行的事务
Posted
技术标签:
【中文标题】Spring JPA 没有正在进行的事务【英文标题】:Spring JPA no transaction is in progress 【发布时间】:2015-05-11 02:08:11 【问题描述】:我是 Spring 和 JPA 的新手,浪费了 5 天时间,搜索互联网没有结果。我想将对象保存到 SQL SERVER,连接正确,但是当我编写 .flush() 时出现异常
嵌套异常是 javax.persistence.TransactionRequiredException: no 交易正在进行中
这是我的 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>
这是我的 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>
这是我的服务实现:
@Service("manService")
public class SaveManImpl implements SaveMan
//
@Autowired
private ManRepositoryImpl manRepo;
@Transactional
public Table1 save(Table1 table)
manRepo.save(table);
return null;
最后是我的存储库实现:
@Repository("manRepository")
public class ManRepositoryImpl implements ManRepository
@PersistenceContext
private EntityManager em;
public Table1 save(Table1 table)
em.persist(table);
em.flush();
return table;
从异常中,Spring 看不到 @Transactional 注释,对吗?我试着把注解放在repository save方法上面,没有结果,在上面这个Service save方法之后,这里也一样。提前致谢
我在控制器中调用 save 方法
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";
错误堆栈:
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)
弹簧配置文件
<?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>
【问题讨论】:
你能发布完整的堆栈跟踪吗? 然后将代码发布到您获得 SaveMan 实例并调用其 save() 方法的位置。顺便说一句:如果注入和使用具体类,为什么要定义接口?如果您的方法返回 null,为什么它会返回 Table1? 看起来你的 jpaContext.xml 配置被切断了。你能修复发布完整的配置,包括 bean 'transactionManager' 的定义 @RohitJain 我用全栈更新了问题 @JBNizet 我从控制器调用它,我已经编辑了代码,请参阅。如果您的方法返回 null,为什么它会返回 Table1?我不在乎它返回什么,我只想将对象保存到 db 【参考方案1】:你有两个 Spring 上下文:
主要的,由 jpaContext.xml 配置,其中来自服务和存储库包的 bean 被扫描,并由事务拦截器代理。
mvc 一个,由另一个 xml 文件(您没有命名)配置,其作用是描述应用程序的 MVC 部分,即定义和配置例如控制器 bean、视图解析器、等等。这个上下文是主上下文的子上下文。
问题在于您还扫描了此子上下文中的服务和存储库包。因此,您最终会得到每个服务和存储库的两个实例:
主要上下文中的一个,它是事务性的 子上下文中的一个,而不是(因为子上下文不关心事务管理)因此,控制器被注入了来自与控制器相同上下文的服务:非事务性的。
要确认这一点,您可以在 bean 的构造函数中添加跟踪,看看它们被实例化了多少次。
为了避免这个问题,有两种解决方案:
避免在 mvc 上下文中扫描存储库和服务包:此上下文应该只关心与 mvc 相关的 bean。当 Spring 在控制器中注入服务时,它不会在 mvc 上下文中找到该服务,因此会查找它,并在主上下文中找到它。事务服务将因此被注入。 使用单一上下文:servlet 之一,其中将定义应用程序中的所有 bean。【讨论】:
你知道你是谁吗?你是我的英雄 !!!非常感谢,我已经从 drispatcher servlet 扫描中删除了服务和存储库,并且它有效。非常感谢! 会过去的,别担心 :) 我在我的 servlet 配置文件中完成了所有的配置,它对我有用,非常感谢你的帮助:) @JBNizet 请你看看这个问题。 ***.com/questions/54457041/… 我认为我们面临着类似的问题,但使用的是 spring boot。 Spring Boot 通过@SpringBootApplication
扫描所有bean,我们不进行任何配置。关于如何避免在 Spring Boot 应用程序中从两个上下文加载 bean 的任何建议?【参考方案2】:
您应该将您的实体管理器介绍给您的事务管理器,这样当您使用@Transactional
注释您的函数时,它会从池中加载实例
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf" />
</bean>
<tx:annotation-driven />
HTH!
【讨论】:
据我所知,如果尚未定义,应用程序将无法启动。它不在发布的配置中,但它必须存在............不是吗? 我已将(也编辑了问题)添加到 jpaContext.xml,但没有结果,仍然:HTTP 状态 500 - 请求处理失败;嵌套异常是 javax.persistence.TransactionRequiredException: no transaction is in progress @alan 是的,AFAIK 是必需的 :) @Misha 你加了?如果以前不存在,我看不到应用程序如何启动。 我现在已经添加了这些配置,因为@JB Nizet 的回答它可以工作【参考方案3】:为了简短起见,请尝试在方法的开头添加@Transactional
。这对我来说是个问题。
【讨论】:
【参考方案4】:我遇到了同样的问题,在我的例子中,我使用了一个带有 @Transactional
注释的 DAO 的库,但它不是来自 Spring 的 org.springframework.transaction.annotation.Transactional
,而是 javax.transaction.Transactional
,无法命名,所以您不能指定 TransactionManager:
@Transactional("transactionManagerName")
public class DaoImpl implements Dao ...
在我的例子中,从一个配置文件中获取它的事务管理器:
@Bean("transactionManagerName")
public PlatformTransactionManager transactionManager()
throws SQLException, NamingException
final HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(this.sessionFactory().getObject());
return transactionManager;
【讨论】:
以上是关于Spring JPA 没有正在进行的事务的主要内容,如果未能解决你的问题,请参考以下文章
TransactionRequiredException:Spring Data JPA 没有正在进行的事务
企业分布式微服务云SpringCloud SpringBoot mybatis (十七)Spring Boot中的事务管理