5

I am using native method of entity manager and I want to rollback when some error occurs.For this I tried @Transactional annotation but this does not rollback.Below is my sample code

controller

@Autowired
ServiceImpl ServiceImpl;

@RequestMapping("/saveinfo")
@ResponseBody
@Transactional
public String saveinfo(Long id)
{
   ServiceImpl.saveInfo(id);
}

Service class

@Autowired
DAOImpl daoImpl;

@Transactional
public String saveinfo(Long id)
{
    daoImpl.saveInfo1(id);
    daoImpl.saveInfo12(id);
    daoImpl.saveInfo12(id);

}

DAO class

@Override
public BigInteger saveInfo11() {

   Query query =  entityManagerUtil.entityManager().createNativeQuery("insert query");
   return (BigInteger)query.getSingleResult();
}

@Override
public BigInteger saveInfo12() {

   Query query =    entityManagerUtil.entityManager().createNativeQuery("insert query");
   return (BigInteger)query.getSingleResult();
}

@Override
public BigInteger saveInfo13() {

   Query query =    entityManagerUtil.entityManager().createNativeQuery("insert query");
   return (BigInteger)query.getSingleResult();
}

Now in the above codes,

If I have some runtime error in saveInfo3() then I want to rollback methods of saveInfo1() and saveInfo2()

This is the way I did but it did not rollback,so Please tell me how to do

EDIT

I tried using

@Transactional(rollbackFor=MyException.class,propagation = Propagation.REQUIRED) and  @Transactional(propagation = Propagation.REQUIRED) and

@Transactional(rollbackFor=MyException.class))

In all the 3 cases ,it did not rollback

Update

applicationcontext.xml



<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"  
       xmlns:aop="http://www.springframework.org/schema/aop" 
       xmlns:context="http://www.springframework.org/schema/context" 
       xmlns:jee="http://www.springframework.org/schema/jee" 
       xmlns:tx="http://www.springframework.org/schema/tx" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:security="http://www.springframework.org/schema/security" 
       xmlns:mongo="http://www.springframework.org/schema/data/mongo"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/aop 
                          http://www.springframework.org/schema/aop/spring-aop-3.0.xsd        
                          http://www.springframework.org/schema/beans 
                          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd         
                          http://www.springframework.org/schema/context 
                          http://www.springframework.org/schema/context/spring-context-3.0.xsd
                           http://www.springframework.org/schema/data/mongo
                          http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd         
                          http://www.springframework.org/schema/jee 
                          http://www.springframework.org/schema/jee/spring-jee-3.0.xsd         
                          http://www.springframework.org/schema/tx  
                          http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
                          http://www.springframework.org/schema/security 
                          http://www.springframework.org/schema/security/spring-security-3.0.xsd
                          http://www.springframework.org/schema/task  
http://www.springframework.org/schema/task/spring-task-3.0.xsd">



     <!--<context:annotation-config />-->
     <context:spring-configured/>

       <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
        <property name="dataSource" ref="dataSource"/>
        <property name="persistenceUnitName" value="persistenceUnit"/>
       </bean>
       <bean id="messageDigestPasswordEncoder" class="org.springframework.security.authentication.encoding.MessageDigestPasswordEncoder">
         <constructor-arg value="SHA-256" />
        </bean>

       <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource"  id="dataSource">
         <property name="driverClassName" value="${database.driverClassName}"/>
        <property name="url" value="${database.url}"/>
        <property name="username" value="${database.username}"/>
        <property name="password" value="${database.password}"/>


    </bean>










     <tx:annotation-driven  mode="aspectj" transaction-manager="transactionManager"/>
       <context:property-placeholder location="classpath*:META-INF/database.properties"/>
       <context:property-placeholder location="classpath*:META-INF/project.properties"/>

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

    <bean id="propertiesUtil" class="com.work.project.utils.PropertiesUtil">

    <property name="locations" >
   <list>
                <value>classpath*:META-INF/*.properties</value>

            </list>
    </property>

</bean>

    <context:component-scan base-package="com.work.project">
        <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
    </context:component-scan>



     <task:executor id="myexecutor" pool-size="5"  />
<task:annotation-driven executor="myexecutor"/>








</beans>

modified controller method

@Autowired
ServiceImpl ServiceImpl;

@RequestMapping("/saveinfo")
@ResponseBody
//Now I dont use transactional annotation in controller class
public String saveinfo(Long id)
{
   ServiceImpl.saveInfo(id);
}

If any more information is required please ask

SpringLearner
  • 13,738
  • 20
  • 78
  • 116
  • I just answered a very similar [question today](http://stackoverflow.com/questions/28696152/spring-transactional-not-starting-a-transaction/28704004#28704004), it might be the same issue. Basically you're using annotation-driven mode="aspectj" but I don't see a `load-time-weaver` defined anywhere in your context. – ikumen Feb 25 '15 at 06:52
  • @user2264997 If I make `` to `` then my application fails to start.I mean when I right on the project and select run on server then it does not start.Wait I will post the error – SpringLearner Feb 25 '15 at 07:04
  • @user2264997 please see this [error](http://pastie.org/9980637) – SpringLearner Feb 25 '15 at 08:11
  • What version of Spring do you use? Can you confirm that the methods annotated with `@Transactional` are in a Spring Bean (defined in the XML file), that gets injected somewhere by Spring itself? – V G Feb 25 '15 at 08:39
  • Could you show me how `entityManagerUtil` is obtained (injected?) and the code of `EntityManagerUtil.entityManager()`? – V G Feb 25 '15 at 08:48
  • @AndreiI Please this http://pastie.org/9980724 and I am using spring 3 – SpringLearner Feb 25 '15 at 09:22
  • Try adding `@Transactional(propagation=Propagation.REQUIRED)` to both `saveInfo(id)` and `saveInfo11()`, `saveInfo12()`, `saveInfo13()`. Another question: what database are you using? – V G Feb 25 '15 at 09:34
  • @AndreiI this is my room http://chat.stackoverflow.com/rooms/44929/java-spring-jpa-php-jquery-javascript-beginners ,If possible come here – SpringLearner Feb 25 '15 at 09:42
  • Please, post the code and/or configuration for `entityManagerUtil` bean. – Roman C Feb 25 '15 at 11:11
  • @RomanC Please come to my chat room – SpringLearner Feb 25 '15 at 11:26
  • I am so glad I dont have this XML configuration stuff anymore. It is time they create a DSL on top of that. So many characters just to express simple everyday configuration needs. Shame... . – Martin Kersten Mar 01 '15 at 21:26

4 Answers4

2

The problem seems to be that the EntityManager is not injected by Spring. The EntityManager instance is created by your utility class entityManagerUtil.entityManager(). This means, that everytime when you use a new EntityManager, they are not part of your method transaction.

In order to solve this problem: let Spring inject correctly the EntityManager (try for example injecting it directly in your original bean with @PersistenceContext and do those three methods directly in the same single method).


UPDATE: The problem was that the code that threw the exception was in a try/catch block, this way, the transaction was not rolled-back by Spring. Transaction is rolled-back only when the transactional method exits with an RuntimeException (by default).

V G
  • 18,822
  • 6
  • 51
  • 89
0

You need to change your method to have rollbackFor property for your @Transactional annotation, so that

@Transactional(rollbackFor=MyException.class)
public String saveinfo(Long id)

Keep in mind, that MyException should be unchecked exception, as checked exceptions thrown from @Transactional method will not result transaction to be rolled back.

Update:

To make sure everything is correct

  1. Check that Spring indeed creates proxy and your method is being executed in transaction (e.g. use TransactionSynchronizationManager.isActualTransactionActive())

  2. Check that MyException.class is indeed unchecked exception (subclass of java.lang.RuntimeException or java.lang.Error)

  3. Check that your exception is indeed thrown (e.g. not catched somehow)

And why your controller saveInfo() is marked as transactional? This it not recommended, only service layer should be marked as transactional. See this post for example.

Community
  • 1
  • 1
vtor
  • 8,989
  • 7
  • 51
  • 67
  • Thanks for the answer,I have tries this before it did not rollback.This rollback only occurs in HQl but not for native queries – SpringLearner Feb 23 '15 at 07:03
  • Can you please update your question with the code you tried? (I updated my answer with some info) – vtor Feb 23 '15 at 07:04
  • I have modified the question – SpringLearner Feb 23 '15 at 07:08
  • Looks like everything is correct. So rollback should work. Just one more time make sure that 1. Spring indeed creates transaction (use TransactionSynchronizationManager.isActualTransactionActive()) 2. MyException is unchecked exception 3. MyException is indeed thrown – vtor Feb 23 '15 at 07:16
  • see this http://pastie.org/9974005 after saveinfo1 and saveinfo2 is run,it will throw nullpointerexception on line 8.So what ever I have inserted in saveinfo1 and saveinfo2 should be rolledback but it did not happen.I check in DB,all the present there – SpringLearner Feb 23 '15 at 07:52
0

Maybe the entityManagerUtil (which you use within your DAO implementation) uses or creates an entity manager, that is not running in the surrounding transaction context. Please have a look at following tutorial: Here the JPA EntityManager is injected with @PersistenceContext

gclaussn
  • 1,736
  • 16
  • 19
0

Can you make sure that your persistenceUnit has configured the following, transaction type(optional) and hibernate.connection.autocommit to false, if not please do so.

<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
        <properties>
            <property name="hibernate.connection.autocommit" value="false" />
        </properties>
    </persistence-unit>

I have excluded other properties for brevity

iamiddy
  • 3,015
  • 3
  • 30
  • 33