web-dev-qa-db-fra.com

Spring JPA aucune transaction n'est en cours

Je suis nouveau sur Spring et JPA, j'ai perdu 5 jours et aucun résultat avec la recherche sur Internet. Je souhaite enregistrer l'objet dans SQL SERVER, la connexion est correcte mais lorsque j'écris .flush (), j'obtiens l'exception

l'exception imbriquée est javax.persistence.TransactionRequiredException: aucune transaction n'est en cours

C'est mon 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>

Voici mon fichier 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>

Voici mon implémentation de service:

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


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

}

Et enfin mon implémentation Repository:

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

    @PersistenceContext
    private EntityManager em;   

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

À l'exception de Spring, Spring ne peut pas voir l'annotation @Transactional, ai-je raison? J'ai essayé de mettre l'annotation au-dessus de la méthode de sauvegarde du référentiel, aucun résultat, après cette méthode de sauvegarde du service ci-dessus, la même chose ici. Merci d'avance

enter image description here

J'appelle la méthode de sauvegarde dans mon contrôleur

    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";
    }   
}

Pile d'erreur:

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)

Fichier de configuration 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

Vous avez deux contextes Spring:

  1. le principal, configuré par jpaContext.xml, où les beans des packages de service et de référentiel sont analysés et mandatés par un intercepteur transactionnel.

  2. celui mvc, configuré par l'autre fichier xml (vous ne l'avez pas nommé) dont le rôle est de décrire la partie MVC de l'application, c'est-à-dire définir et configurer par exemple les beans contrôleur, le résolveur de vue, etc. Ce contexte est un enfant du principal.

Le problème est que vous analysez également les packages de service et de référentiel dans ce contexte enfant. Vous vous retrouvez ainsi avec deux instances de chaque service et référentiel:

  • un dans le contexte principal, qui est transactionnel
  • une dans le contexte enfant, qui ne l'est pas (puisque le contexte enfant ne se soucie pas de la gestion des transactions)

Le contrôleur est ainsi injecté avec un service provenant du même contexte que le contrôleur: le non transactionnel.

Pour confirmer cela, vous pouvez ajouter des traces dans le constructeur des beans et voir combien de fois elles sont instanciées.

Et pour éviter le problème, il existe deux solutions:

  • évitez d'analyser le référentiel et les packages de services dans le contexte mvc: ce contexte ne doit s'intéresser qu'aux beans liés à mvc. Lorsque Spring injecte un service dans un contrôleur, il ne trouverait donc pas le service dans le contexte mvc, et donc le rechercherait, et le trouverait dans le contexte principal. Le service transactionnel serait ainsi injecté.
  • utiliser un seul contexte: celui du servlet, où tous les beans de l'application seraient définis.
26
JB Nizet

Vous devez présenter votre gestionnaire d'entités à votre gestionnaire de transactions, de sorte que lorsque vous annotez votre fonction avec @Transactionalit charge les instances du pool

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

HTH!

9
karthik manchala

Pour faire court, essayez d'ajouter @Transactional au tout début de votre méthode. C'était un problème dans mon cas.

4
Damir Olejar