newcoder
newcoder

Reputation: 492

Spring @Trasactional is not rolling back while there is an exception

I am new to spring and working on a sample program using Spring jdbc. this is to check how spring @Trsactional working and rolling back the changes to the Db if there is an exception.

But I am not able to achieve this. Through I am raising an exception in one of the DB update, still it's inserting the data to DB and not rolling back.

I know somewhere I am making mistake but not able to figure it out. Not sure if this is a correct approach.

What I am doing :-

  1. in main methis I am calling load methos of Global class (which has jdbcTemplate as satic member as I will this jdbcTemplate to all other classes)

  2. Global class load methos will initiate the bean using ApplicationContext.

  3. Creating Dbclass instance in main method and sending the jdbcTemplate as parameter.

4.creating some sample data and calling executeDb method.

5.execute DB method will create the instance of other Dbclasss and setting the jdbcTemplate which earlier I initialized using bean in main method (I have separate class for each operation - like createuser, UpdataBalance etc)

  1. then it will call the db opration method to insert data (I am using batchupdate)

EDIT - Removed all try-catch

DB opration code:-

@Transactional(rollbackFor={Exception.class})
    public void executeDB(int count) throws Exception
    {

                CreateAccount newacc = new CreateAccount(jdbcTemplate);
                CreateUser newusr = new CreateUser(jdbcTemplate);
                //BalanceUpdate newbal = new BalanceUpdate(jdbcTemplate);
                newacc.addList(acclist);
                newusr.addToList(usrlist);
                //newbal.addList(ballist);

                newusr.execute(); // insert data to db
                newacc.addAccount(); // insert data to db
                //newbal.addBalance(); // insert data to db

                newacc.getAccList().clear();
                newusr.getUserList().clear();
                //newbal.getBalanceList().clear();
                if(count == 5000)
                {
                    Thread.sleep(1000);
                    throw new Exception("Rollback");
                }
                count += 1000;
                //throw new Exception();


        }
<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-xml -->

    <context:component-scan base-package="com.example"></context:component-scan>

    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
        <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
        <property name="username" value="system"/>
        <property name="password" value="root"/>
    </bean>


    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">  
    <property name="dataSource" ref="dataSource"></property>  
    </bean> 

    <bean id="startit" class="com.example.springtransaction.GlobalClass">  
    <property name="jdbcTemplate" ref="jdbcTemplate"></property>  
    </bean> 
<bean id="dbupdate" class="com.example.springtransaction.DbUpdate">  
<property name="jdbcTemplate" ref="jdbcTemplate"></property>  
</bean>

Upvotes: 0

Views: 353

Answers (2)

Chris Sekas
Chris Sekas

Reputation: 159

You should remove the try - catch and define that the method throws an Exception. Something like that

    @Transactional(rollbackFor={Exception.class}) 
    public void executeDB() throws Exception
    {
       if(usrlist.size() >= 5) 
       { 
           CreateAccount newacc = new CreateAccount(jdbcTemplate);
           CreateUser newusr = new CreateUser(jdbcTemplate);
           BalanceUpdate newbal = new BalanceUpdate(jdbcTemplate);
           newacc.addList(acclist);
           newusr.addToList(usrlist);
           newbal.addList(ballist);
           newusr.execute(); // insert data to db
           newacc.addAccount(); // insert data to db
           newbal.addBalance(); // insert data to db - raise exception here 
        }
    }

Update

The class that contain the executeDB() method should be a @Component and inject that component in the main class. Not create a new Dbclass() instance by your own.

In high-level the reason is that the Spring creates proxy classes upon injection for classes that declare @Transactional. You could read more about Aspect-Oriented Programming here.

Upvotes: 0

Ivan
Ivan

Reputation: 8758

You need to throw exception from your method not silently log it in catch block. And for checked exceptions you need to use @Transactional(rollbackFor = {Exception.class}). http://www.logicbig.com/tutorials/spring-framework/spring-data-access-with-jdbc/transactional-roll-back/ https://www.catalysts.cc/en/wissenswertes/spring-transactional-rollback-on-checked-exceptions/

Upvotes: 2

Related Questions