28

I am new to Spring and JPA, wasted 5 days and no result with searching internet. I want to save object to SQL SERVER, connection is correct but when I write .flush() I get the exception

nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress

This is my 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:

<?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 ? I tried to put the annotation above repository save method, no result, after this above Service save method, the same here. Thanks in advance

enter image description here

I call the save method in my 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

<?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>
Misha Akopov
  • 12,241
  • 27
  • 68
  • 82
  • 1
    Can you post the full stack trace? – Rohit Jain Mar 09 '15 at 19:25
  • And post the code where you get an instance of SaveMan and call its save() method. BTW: why do you define interfaces if you inject and use the concrete class? Why does your method return a Table1 if it returns null? – JB Nizet Mar 09 '15 at 19:28
  • It looks like your jpaContext.xml config is cut off.Can you fix to post full config, including the definition of the bean 'transactionManager' – Alan Hay Mar 09 '15 at 19:32
  • @RohitJain I have updated question with full stack – Misha Akopov Mar 09 '15 at 19:43
  • 1
    @JBNizet I call it from controller, I have edited the code, please see. Why does your method return a Table1 if it returns null? I don't care what it returns, I just want to save object to db – Misha Akopov Mar 09 '15 at 19:46
  • Please post the spring-mvc xml configuration (i.e. the configuration associated to the dispatcher servlet). – JB Nizet Mar 09 '15 at 19:50
  • @JBNizet Updated the question, please see the configuration – Misha Akopov Mar 09 '15 at 19:53

7 Answers7

36

You have two Spring contexts:

  1. the main one, configured by jpaContext.xml, where beans from the service and repository packages are scanned, and proxied by a transactional interceptor.

  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, i.e. define and configure for example the controller beans, the view resolver, etc. This context is a child of the main one.

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.

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. 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. 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.
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • 8
    You know who you are ? You are my hero !!! Thank you very much, I have removed from drispatcher servlet scan for service and repository and it worked. Thank you very much ! – Misha Akopov Mar 09 '15 at 20:06
  • 8
    That will pass, don't worry :) – JB Nizet Mar 09 '15 at 20:07
  • i did all my configrations in my servlet config file and it worked for me, thanks alot for your help:) – athena Sep 12 '15 at 16:32
  • @JBNizet could you take a look at this question please. https://stackoverflow.com/questions/54457041/spring-boot-repository-does-not-save-to-the-db-if-called-from-scheduled-job – Fanooos Jan 31 '19 at 12:21
  • I think we are facing similar issue but using spring boot. All the beans are scanned by spring boot via `@SpringBootApplication` and we do not configure anything. Any suggestion about how we can avoid beans being loaded from two contexts in a spring boot app? – Julian Aug 05 '20 at 23:54
  • Any luck @Julian – bibliophilsagar Aug 11 '20 at 17:25
  • No unfortunately. I am still professionally interested to understand what is causing this.Using spring since 2007. I raised this https://stackoverflow.com/questions/63255815/spring-transaction-synchronisation-not-working-transactionaleventlistener and hope someone will give me some clues. To solve our problem I switched back to programatic transaction management. Not what spring encourages us to do but I could not spend more project time on the issue. – Julian Aug 12 '20 at 07:57
  • @Julian Same here. I wish we had more control over that. Now that it's 2023 and Spring is all annotation based, I don't know what means "avoid scanning the repository". My application connects to 2 databases, hence I have 2 'at'EnableJpaRepositories. I don't have any repository ('at'Repository) because I have no use for them. I would want transactions only for updating one db, I'm using 'at'Transactional. Still, I have this error. – Patrice Gagnon Mar 17 '23 at 19:04
12

You should introduce your entity manager to your transaction manager, so that when you annotate your function with @Transactionalit loads instances from the pool

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

HTH!

karthik manchala
  • 13,492
  • 1
  • 31
  • 55
  • As far as I can see the application would not start if this was not already defined. It's not in the posted config but it must exist.........No? – Alan Hay Mar 09 '15 at 19:48
  • I have added (also edited the question) to jpaContext.xml, but nore result, still : HTTP Status 500 - Request processing failed; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress – Misha Akopov Mar 09 '15 at 19:50
  • @alan yes it is required AFAIK :) – karthik manchala Mar 09 '15 at 19:52
  • @Misha You have added? I fail to see how the application could even start if this wasn't there before. – Alan Hay Mar 09 '15 at 19:56
  • I have added those config now and it works because of @JB Nizet answer – Misha Akopov Mar 09 '15 at 20:08
6

To make the story short, try adding @Transactional at the very beginning of your method. That was an issue in my case.

3xCh1_23
  • 1,491
  • 1
  • 20
  • 39
2

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

use in Hibernate properties

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

0

If you manage your transaction manually, you join the transaction via joinTransaction()

entityManager.joinTransaction();
entityManager.persist();
entityManager.flush();

That works for me.

0

add method reference public Table1 save(Table1 table) to your SaveMan interface. this happens because you have used dependency injection in the main controller and the spring context has not detected your method properly.

Tiran
  • 31
  • 1
  • 4