Page 1 of 2 12 LastLast
Results 1 to 10 of 16

Thread: no rollback

  1. #1
    Join Date
    Mar 2009
    Posts
    9

    Default no rollback

    Hello,
    Being a newbie to Spring and
    for gaining some experience with the declarative transaction management, I started with the recommended pattern:
    transactional service calls several DAO methods. My service calls two
    DAO methods.
    Although I generate a runtime-exception in the second method there is no rollback of the previous insert.
    I hope, someone finds a "stupid" error.

    Here is the code:

    Code:
    public class SimpleDataDao extends HibernateDaoSupport {
    
        public SimpleData getSimpleData(Integer simpleDataId) {
    	    return (SimpleData) getHibernateTemplate().get(SimpleData.class,
    		    simpleDataId);
        }
    
        public Integer saveSimpleData(SimpleData simpleData) {
    	 Integer ret = (Integer) getHibernateTemplate().save(simpleData);
    	 return ret;
        }
        
        public void failingMethod() {
    	 if(true){
                 throw new RuntimeException("testing");
             }
        }
    }
    
    -----------------------------------------------------
    
    @Transactional  
    public class SimpleDataService  {
        private SimpleDataDao simpleDataDao;
    
        public void complexOp() {
    	SimpleData sp = new SimpleData();
    	sp.setName("dummy1");
    	simpleDataDao.saveSimpleData(sp);
    	simpleDataDao.failingMethod();
        }
      
        public SimpleDataDao getSimpleDataDao() {
            return simpleDataDao;
        }
    
        public void setSimpleDataDao(SimpleDataDao simpleDataDao) {
            this.simpleDataDao = simpleDataDao;
        }
    }
    
    -----------------------------------------------
    public class MainToTest {
    
        public static void main(String[] args) {
    	try {
    	    ClassPathResource res = new ClassPathResource("applicationContext.xml");
    	    XmlBeanFactory factory = new XmlBeanFactory(res);
    	    SimpleDataService service = (SimpleDataService)factory.getBean("simpleDataService");
    	 
    	    service.complexOp();
    	} catch (Exception e) {
    	    System.out.println(e);
    	}
        }
    }

    Here are the configurations:
    applicationContext.xml
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"
           default-autowire="byType">
    
    	<import resource="databaseContext.xml"/>
    	<import resource="transactionContext.xml"/>
    
        <bean id="simpleDataDao" class="x.y.dao.SimpleDataDao">
            <property name="sessionFactory" ref="sessionFactory"/>
        </bean>
    
    	<bean name="simpleDataService" class="x.y.service.SimpleDataService">
    		<property name="simpleDataDao" ref="simpleDataDao"/>
        </bean>
    </beans>

    databaseContext.xml
    Code:
    <?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:jee="http://www.springframework.org/schema/jee"
    	xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd"
    	default-autowire="byType">
    
    	<!-- Database -->
    	<bean id="sessionFactory"
    		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    		<property name="dataSource" ref="dataSource" />
    		<property name="annotatedClasses">
    			<list>
    				<value>x.y.domain.SimpleData</value>
    			</list>
    		</property>
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
    				<prop key="hibernate.hbm2ddl.auto">create</prop>
    				<prop key="hibernate.jdbc.batch_size">0</prop>
    				<prop key="hibernate.show_sql">true</prop>
    				<prop key="hibernate.format_sql">true</prop>
    				<prop key="hibernate.cache.use_second_level_cache">
    					false
    				</prop>
    				<!--prop key="hibernate.cache.use_second_level_cache">true</prop-->
    				<prop key="hibernate.cache.use_query_cache">false</prop>
    				<prop key="hibernate.autocommit">false</prop>
    				
    				<!--prop key="hibernate.cache.use_query_cache">true</prop-->
    				<prop key="hibernate.cache.provider_class">
    					net.sf.ehcache.hibernate.SingletonEhCacheProvider
    				</prop>
    			</props>
    		</property>
    	</bean>
    	 
    	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    		<property name="driverClass" value="oracle.jdbc.driver.OracleDriver" />
    		<property name="jdbcUrl" value="jdbc:oracle:thin:@kfcorcl10:1521:fact" />
    		<property name="user" value="TS" />
    		<property name="password" value="TS" />
    	</bean>
    </beans>
    transactionContext.xml:
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans default-init-method="init" default-destroy-method="destroy" 
    	xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:aop="http://www.springframework.org/schema/aop"
    	xmlns:tx="http://www.springframework.org/schema/tx"
    	xsi:schemaLocation="
    	http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
    	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
    	   
         
        <bean id="transactionManager"
              class="org.springframework.orm.hibernate3.HibernateTransactionManager">
            <property name="sessionFactory" ref="sessionFactory"/>
            <property name="dataSource" ref="dataSource"/> 
        </bean>
        
        <tx:annotation-driven transaction-manager="transactionManager"/>
    </beans>

  2. #2
    Join Date
    Mar 2009
    Location
    Rochester, NY
    Posts
    2

    Default

    Try not catching the exception in your test method.

    Bob

  3. #3
    Join Date
    Mar 2009
    Posts
    9

    Default

    I tried both versions (with and without catching). Behavior is the same (i.e. no rollback)

  4. #4
    Join Date
    Mar 2009
    Posts
    9

    Default

    Hello,
    Here are the log statements. Perhaps there one could find an explanation
    for the missing rollback

    Code:
    2009-03-23 10:10:14,184 DEBUG [com.mchange.v2.resourcepool.BasicResourcePool] - trace com.mchange.v2.resourcepool.BasicResourcePool@ef894ce [managed: 3, unused: 2, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@3c6833f2)
    2009-03-23 10:10:14,186 DEBUG [org.hibernate.tool.hbm2ddl.SchemaExport] - 
        drop table SimpleData
    2009-03-23 10:10:14,189 DEBUG [org.hibernate.tool.hbm2ddl.SchemaExport] - 
        drop sequence hibernate_sequence
    2009-03-23 10:10:14,190 DEBUG [org.hibernate.tool.hbm2ddl.SchemaExport] - 
        create table SimpleData (
            id int4 not null,
            commentary varchar(255),
            name varchar(255),
            primary key (id)
        )
    2009-03-23 10:10:14,247 DEBUG [org.hibernate.tool.hbm2ddl.SchemaExport] - 
        create sequence hibernate_sequence
    2009-03-23 10:10:14,249 INFO [org.hibernate.tool.hbm2ddl.SchemaExport] - schema export complete
    2009-03-23 10:10:14,249 DEBUG [com.mchange.v2.resourcepool.BasicResourcePool] - trace com.mchange.v2.resourcepool.BasicResourcePool@ef894ce [managed: 3, unused: 2, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@3c6833f2)
    2009-03-23 10:10:14,249 DEBUG [org.hibernate.impl.SessionFactoryImpl] - Checking 0 named HQL queries
    2009-03-23 10:10:14,249 DEBUG [org.hibernate.impl.SessionFactoryImpl] - Checking 0 named SQL queries
    2009-03-23 10:10:14,250 DEBUG [org.springframework.beans.factory.xml.XmlBeanFactory] - Finished creating instance of bean 'sessionFactory'
    2009-03-23 10:10:14,250 DEBUG [org.springframework.beans.factory.xml.XmlBeanFactory] - Finished creating instance of bean 'sessionFactory'
    2009-03-23 10:10:14,256 DEBUG [org.springframework.beans.factory.xml.XmlBeanFactory] - Invoking afterPropertiesSet() on bean with name 'simpleDataDao'
    2009-03-23 10:10:14,256 DEBUG [org.springframework.beans.factory.xml.XmlBeanFactory] - Invoking afterPropertiesSet() on bean with name 'simpleDataDao'
    2009-03-23 10:10:14,256 DEBUG [org.springframework.beans.factory.xml.XmlBeanFactory] - Finished creating instance of bean 'simpleDataDao'
    2009-03-23 10:10:14,256 DEBUG [org.springframework.beans.factory.xml.XmlBeanFactory] - Finished creating instance of bean 'simpleDataDao'
    2009-03-23 10:10:14,257 DEBUG [org.springframework.beans.factory.xml.XmlBeanFactory] - Finished creating instance of bean 'simpleDataService'
    2009-03-23 10:10:14,257 DEBUG [org.springframework.beans.factory.xml.XmlBeanFactory] - Finished creating instance of bean 'simpleDataService'
    2009-03-23 10:10:14,264 DEBUG [org.springframework.orm.hibernate3.SessionFactoryUtils] - Opening Hibernate Session
    2009-03-23 10:10:14,264 DEBUG [org.springframework.orm.hibernate3.SessionFactoryUtils] - Opening Hibernate Session
    2009-03-23 10:10:14,284 DEBUG [org.hibernate.impl.SessionImpl] - opened session at timestamp: 12377994142
    2009-03-23 10:10:14,286 DEBUG [org.hibernate.jdbc.AbstractBatcher] - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
    2009-03-23 10:10:14,286 DEBUG [org.hibernate.jdbc.ConnectionManager] - opening JDBC connection
    2009-03-23 10:10:14,286 DEBUG [com.mchange.v2.resourcepool.BasicResourcePool] - trace com.mchange.v2.resourcepool.BasicResourcePool@ef894ce [managed: 3, unused: 2, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@3c6833f2)
    2009-03-23 10:10:14,287 DEBUG [org.hibernate.SQL] - 
        select
            nextval ('hibernate_sequence')
    Hibernate: 
        select
            nextval ('hibernate_sequence')
    2009-03-23 10:10:14,295 DEBUG [org.hibernate.id.SequenceGenerator] - Sequence identifier generated: 1
    2009-03-23 10:10:14,295 DEBUG [org.hibernate.jdbc.AbstractBatcher] - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
    2009-03-23 10:10:14,296 DEBUG [org.hibernate.event.def.AbstractSaveEventListener] - generated identifier: 1, using strategy: org.hibernate.id.SequenceGenerator
    2009-03-23 10:10:14,303 DEBUG [org.springframework.orm.hibernate3.HibernateTemplate] - Eagerly flushing Hibernate session
    2009-03-23 10:10:14,303 DEBUG [org.springframework.orm.hibernate3.HibernateTemplate] - Eagerly flushing Hibernate session
    2009-03-23 10:10:14,303 DEBUG [org.hibernate.event.def.AbstractFlushingEventListener] - processing flush-time cascades
    2009-03-23 10:10:14,303 DEBUG [org.hibernate.event.def.AbstractFlushingEventListener] - dirty checking collections
    2009-03-23 10:10:14,304 DEBUG [org.hibernate.event.def.AbstractFlushingEventListener] - Flushed: 1 insertions, 0 updates, 0 deletions to 1 objects
    2009-03-23 10:10:14,304 DEBUG [org.hibernate.event.def.AbstractFlushingEventListener] - Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
    2009-03-23 10:10:14,305 DEBUG [org.hibernate.pretty.Printer] - listing entities:
    2009-03-23 10:10:14,305 DEBUG [org.hibernate.pretty.Printer] - x.y.domain.SimpleData{id=1, commentary=null, name=dummy1}
    2009-03-23 10:10:14,307 DEBUG [org.hibernate.jdbc.AbstractBatcher] - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
    2009-03-23 10:10:14,307 DEBUG [org.hibernate.SQL] - 
        insert 
        into
            SimpleData
            (commentary, name, id) 
        values
            (?, ?, ?)
    Hibernate: 
        insert 
        into
            SimpleData
            (commentary, name, id) 
        values
            (?, ?, ?)
    2009-03-23 10:10:14,308 DEBUG [org.hibernate.jdbc.AbstractBatcher] - Executing batch size: 1
    2009-03-23 10:10:14,311 DEBUG [org.hibernate.jdbc.AbstractBatcher] - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
    2009-03-23 10:10:14,311 DEBUG [org.springframework.orm.hibernate3.SessionFactoryUtils] - Closing Hibernate Session
    2009-03-23 10:10:14,311 DEBUG [org.springframework.orm.hibernate3.SessionFactoryUtils] - Closing Hibernate Session
    2009-03-23 10:10:14,311 DEBUG [org.hibernate.jdbc.ConnectionManager] - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
    2009-03-23 10:10:14,312 DEBUG [com.mchange.v2.resourcepool.BasicResourcePool] - trace com.mchange.v2.resourcepool.BasicResourcePool@ef894ce [managed: 3, unused: 2, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@3c6833f2)
    2009-03-23 10:10:14,312 DEBUG [org.hibernate.jdbc.ConnectionManager] - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
    java.lang.RuntimeException: testing

  5. #5
    Join Date
    Sep 2008
    Posts
    13

    Default

    About your application, you can read the reference :

    "The Spring team's recommendation is that you only annotate concrete classes with the @Transactional
    annotation, as opposed to annotating interfaces. You certainly can place the @Transactional annotation on an
    interface (or an interface method), but this will only work as you would expect it to if you are using
    interface-based proxies. The fact that annotations are not inherited means that if you are using class-based
    proxies (proxy-target-class="true") or the weaving-based aspect (mode="aspectj") then the transaction
    settings will not be recognised by the proxying/weaving infrastructure and the object will not be wrapped in a
    transactional proxy (which would be decidedly bad). So please do take the Spring team's advice and only
    annotate concrete classes (and the methods of concrete classes) with the @Transactional annotation.
    Note: In proxy mode (which is the default), only 'external' method calls coming in through the proxy will be
    intercepted. This means that 'self-invocation', i.e. a method within the target object calling some other method
    of the target object, won't lead to an actual transaction at runtime even if the invoked method is marked with
    @Transactional!
    Consider the use of AspectJ mode (see below) if you expect self-invocations to be wrapped with transactions as
    well. In this case, there won't be a proxy in the first place; instead, the target class will be 'weaved' (i.e. its byte
    code will be modified) in order to turn @Transactional into runtime behavior on any kind of method."

  6. #6
    Join Date
    Mar 2009
    Posts
    9

    Default

    Do I have any self-invocations? Sorry, I cannot see my mistake.

  7. #7
    Join Date
    Mar 2009
    Posts
    9

    Default

    Ok, now it works.
    One has to use ApplictationContext to get the beans (and use interfaces to get Proxies).

  8. #8
    Join Date
    May 2008
    Posts
    10

    Default

    Hi,

    I have been trying to do the same thing as you have done. But, for me it still doesn't work. Can you please post the code which helped you make it work.

    Thanks and Regards
    Ritesh

  9. #9
    Join Date
    Mar 2009
    Posts
    9

    Default

    Here is the version that works.

    applicationContext.xml (this time I put it all in one file):
    Code:
    <?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
    
    	 
        <bean id="simpleDataDao" class="x.y.dao.SimpleDataDao">
            <property name="sessionFactory" ref="sessionFactory"/>
        </bean>
    
    	<bean name="simpleDataService" class="x.y.service.SimpleDataService">
    		<property name="simpleDataDao" ref="simpleDataDao"/>
        </bean>
        
        <bean name="overService" class="x.y.service.Overservice">
    		<property name="sds" ref="simpleDataService"/>
        </bean>
        
        
        <!-- database settings -->
        
        	<bean id="sessionFactory"
    		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    		<property name="dataSource" ref="dataSource" />
    		<property name="annotatedClasses">
    			<list>
    				<value>x.y.domain.SimpleData</value>
    			</list>
    		</property>
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop> 
    				<prop key="hibernate.hbm2ddl.auto">create</prop>
    				<prop key="hibernate.show_sql">true</prop>
    				<prop key="hibernate.format_sql">true</prop>
    			</props>
    		</property>
    	</bean>
    	 
    	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    		<property name="driverClass" value="oracle.jdbc.driver.OracleDriver" />
    		<property name="jdbcUrl" value="jdbc:oracle:thin:@kfcorcl10:1521:fact" />
    		<property name="user" value="TS" />
    		<property name="password" value="TS" />
    	</bean>
    	
    	<!--  transaction settings  -->
    	<tx:annotation-driven transaction-manager="transactionManager" />  
    	 
        
        <bean id="transactionManager"
              class="org.springframework.orm.hibernate3.HibernateTransactionManager">
            <property name="sessionFactory" ref="sessionFactory"/>
        </bean>
    </beans>

    Use interfaces for your classes and use ApplicationContext instead of
    Beanfactory:

    Code:
    package x.y.dao;
    
    import x.y.domain.SimpleData;
    
     
    public interface ISimpleDataDao {
        
        public Integer saveSimpleData(SimpleData simpleData);
        public void failingMethod();
    }
    
    ----------------------------------------------------------------
    
    package x.y.dao;
    
    import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
    
    import x.y.domain.SimpleData;
    
     
    public class SimpleDataDao extends HibernateDaoSupport implements ISimpleDataDao{
    
        public SimpleData getSimpleData(Integer simpleDataId) {
    	    return (SimpleData) getHibernateTemplate().get(SimpleData.class,
    		    simpleDataId);
        }
    
        public Integer saveSimpleData(SimpleData simpleData) {
    	 Integer ret = (Integer) getHibernateTemplate().save(simpleData);
    	 return ret;
        }
        
        public void failingMethod() {
    	 if(true){
                 throw new RuntimeException("testing");
             }
        }
    }
    
    --------------------------------------------------------------------
    package x.y.domain;
    
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
     
    @Entity
    @Table(name = "SimpleData")
    public class SimpleData {
        private Integer id;
        private String name;
        private String commentary;
        
        
        /**
         * Default-Konstruktor fuer Hibernate.
         */
        public SimpleData() {
        }
        
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer anId) {
            this.id = anId;
        }
    
        /**
         * @return the name
         */
        public String getName() {
            return name;
        }
    
        /**
         * @param name the name to set
         */
        public void setName(String name) {
            this.name = name;
        }
    
        /**
         * @return the commentary
         */
        public String getCommentary() {
            return commentary;
        }
    
        /**
         * @param commentary the commentary to set
         */
        public void setCommentary(String commentary) {
            this.commentary = commentary;
        }
    }
    
    --------------------------------------------------------------------
    
    package x.y.service;
    
     
    public interface ISimpleDataService {
        public void complexOp();
    }
    
    ---------------------------------------------------------------------
    
    package x.y.service;
    
    import org.springframework.transaction.annotation.Transactional;
    
    import x.y.dao.ISimpleDataDao;
    import x.y.domain.SimpleData;
    
     
    public class SimpleDataService implements ISimpleDataService{
        private ISimpleDataDao simpleDataDao;
    
        
        @Transactional
        public void complexOp() {
    	SimpleData sp = new SimpleData();
    	sp.setName("dummy1");
    	simpleDataDao.saveSimpleData(sp);
    	simpleDataDao.failingMethod();
        }
      
        public void setSimpleDataDao(ISimpleDataDao simpleDataDao) {
            this.simpleDataDao = simpleDataDao;
        }
    }
    
    ----------------------------------------------------------------
    
    package x.y.test;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import x.y.service.ISimpleDataService;
    
     
    public class MainToTest {
    
        public static void main(String[] args) {
    	try {
    	    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    	    ISimpleDataService s = (ISimpleDataService)ctx.getBean("simpleDataService");
    	    s.complexOp();
    	} catch (Exception e) {
    	    System.out.println(e);
    	}
        }
    }

  10. #10
    Join Date
    May 2008
    Posts
    10

    Default

    Hi,

    Thanks for posting the code. It was immensely helpful. My JUnit test case now works fine and it is able to rollback on exception.

    I have another weird problem though. When I use the same code in my application, the logs now say that the rollback was done. But when I check my database, the inserted record is still present. This is different from what I saw in my JUnit Test Case. In the JUnit Test case the record was not present which is what is expected.

    I am using Spring 2.5.6, Hibernate 3.3.1GA, Oracle 10g and Tomcat 6.0.18.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •