Hibernate, Spring --> kein Rollback

yogitobi

Grünschnabel
Hallo zusammen,
ich mache gerade meine ersten Schritte mit Spring. Insbesondere interessiert mich
das Transaction-Management. Als ersten Test wollte ich das Pattern
"Service (Transaktions-geklammert) ruft DAOs auf" implementieren.
Um den Rollback zu testen, habe ich eine explizite Fehlermethode programmiert.
Leider kommt es nie zu einem Rollback.

Ich hoffe, einige von euch Experten können mir helfen.
Danke im Voraus.

Gruß
Tobias



Hier sind die entsprechenden Code-Teile:


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

Es ist übrigens egal ob ich die Exception abfange oder nicht. In beiden Fällen
gibt es kein Rollback.




Hier sind die Spring Konfigurationen:
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>


Logging:
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
 
Ich vermute du bekommst beim Lookup der Bean eine ungeproxierte Instanz zurück, d.h. eine Instanz ohne den Transaktionalen Proxy davor. Es scheint auch desweiteren so, dass überhaupt keine Transaktion ausgelöst wird. Was mich bei dem Ganzen etwas wundert, ist, dass beim Hochfahren des Context keine Exception fliegt. Lange Rede, kurzer Sinn...

1. Führ mal für den Service ein Interface ein und mach den Lookup über diesen. Normalerweise muss man, wenn man direkt Klassen benutzt die Proxies mit CGLib erzeugen lassen (extra Einstellungen in der Config). Spring erzeugt nämlich per default Delegateproxies und keine Inheritanceproxies. Also: Interface mit der Businessmethode anlegen, deine Implementierung dieses implementieren lassen und beim Lookup auf das Interface casten.

2. Dreh mal die Loglevels für das tx Package hoch... dann sieht man besser, was da Transaktional vor sich geht.

Kleinigkeiten noch: Du brauchst den Umweg über dei BeanFactory nicht zu machen. ApplicationContext ctx = new ClassPathXmlApplicationContext("config.xml"); reicht.

REINHAUN!
 

Neue Beiträge

Zurück