web-dev-qa-db-ja.com

Spring JPAトランザクションは進行中です

私はSpringとJPAを初めて使いますが、5日間無駄になりますが、インターネットを検索しても結果はありません。オブジェクトをSQL SERVERに保存したい、接続は正しいが、.flush()を書き込むと例外が発生する

ネストされた例外はjavax.persistence.TransactionRequiredExceptionです:進行中のトランザクションはありません

これは私の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アノテーションを見ることができません。ここで、上記のサービスの保存方法の後に、リポジトリの保存方法の上に注釈を配置しようとしましたが、結果はありません。前もって感謝します

enter image description here

コントローラーで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)

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>
12
Misha Akopov

2つのSpringコンテキストがあります。

  1. jpaContext.xmlによって構成された主なもの。サービスおよびリポジトリパッケージのBeanがスキャンされ、トランザクションインターセプターによってプロキシされます。

  2. アプリケーションのMVC部分を記述する役割を持つ他のxmlファイル(名前は付けませんでした)によって構成されたmvcファイル。たとえば、コントローラーBean、ビューリゾルバーなどを定義および構成します。このコンテキストはメインの子。

問題は、この子コンテキストでサービスとリポジトリパッケージもスキャンすることです。したがって、各サービスとリポジトリの2つのインスタンスになります。

  • 1つはメインコンテキストにあり、トランザクションです
  • 子コンテキストではない(子コンテキストはトランザクション管理を気にしないため)

したがって、コントローラーには、コントローラーと同じコンテキスト(トランザクションではないコンテキスト)からのサービスが注入されます。

それを確認するために、Beanのコンストラクターにトレースを追加し、それらがインスタンス化される回数を確認できます。

そして、問題を回避するために、2つの解決策があります。

  • mvcコンテキストでリポジトリおよびサービスパッケージをスキャンしないでください。このコンテキストでは、mvc関連のBeanのみを考慮する必要があります。 Springがコントローラーにサービスを注入すると、mvcコンテキストでサービスを見つけられないため、検索してメインコンテキストで見つけます。したがって、トランザクションサービスが注入されます。
  • 単一のコンテキストを使用します:アプリケーション内のすべてのBeanが定義されるサーブレットのコンテキスト。
26
JB Nizet

ストーリーを短くするには、メソッドの最初に@Transactionalを追加してみてください。それは私の場合の問題でした。

4
Damir Olejar