PDA

View Full Version : Cannot rollback tx when using TransactionProxyFactoryBean



amd700
Dec 6th, 2004, 02:37 AM
Hi all,
I have encountered a problem when using Spring Transaction Management feature.
The following sources are based on the example petClinic sources.
But the TransactionProxyFactoryBean seem go wrong (maybe) when I intentionally throw a DataAccessException in storeComposite method.
The transaction still commit instead rollback.
Please help me. Thank you



--------- composite.hbm.xml -----------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http&#58;//hibernate.sourceforge.net/hib...g-2.0.dtd">

<hibernate-mapping auto-import="true">
<class name="example.framework.model.CompositeModel" table="Composite">
<id name="id" type="int" unsaved-value="-1">
<generator class="assigned"/>
</id>

<set name="children" lazy="false" cascade="all">
<key column="parent_id"/>
<one-to-many class="example.framework.model.CompositeModel"/>
</set>

<property name="parentId" column="parent_id" type="java.lang.Integer"/>
<property name="name" type="java.lang.String"/>
<property name="description" type="java.lang.String"/>
</class>
</hibernate-mapping>



----------------jdbc.properties ---------------
jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc&#58;hsqldb&#58;hsql&#58;//localhost&#58;9001
jdbc.username=sa
jdbc.password=

hibernate.dialect=net.sf.hibernate.dialect.HSQLDia lect



----------------- applicationContext.xml -----------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http&#58;//www.springframework.org/dtd/s...beans.dtd">
<beans>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyP laceholderConfigurer">
<property name="location"><value>jdbc.properties</value></property>
</bean>

<!-- Local DataSource that works in any environment -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerD ataSource">
<property name="driverClassName"><value>$&#123;jdbc.driverClassName&#125;</value></property>
<property name="url"><value>$&#123;jdbc.url&#125;</value></property>
<property name="username"><value>$&#123;jdbc.username&#125;</value></property>
<property name="password"><value>$&#123;jdbc.password&#125;</value></property>
</bean>

<!-- Hibernate SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFact oryBean">
<property name="dataSource"><ref local="dataSource"/></property>
<property name="mappingResources">
<value>composite.hbm.xml</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">$&#123;hibernate.dialect&#125;</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>

<!-- Transaction manager for a single Hibernate SessionFactory &#40;alternative to JTA&#41; -->
<bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransac tionManager">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>


<bean id="compositeTarget" class="example.framework.persistent.CompositePMImpl">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>

<bean id="proxy" class="org.springframework.transaction.interceptor.Transa ctionProxyFactoryBean">
<property name="transactionManager"><ref local="transactionManager"/></property>
<property name="target"><ref local="compositeTarget"/></property>
<property name="transactionAttributes">
<props>
<prop key="store*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>

</beans>


------------- CompositeModel.java --------------------
package example.framework.model;

import java.util.Iterator;
import java.util.Set;

public class CompositeModel &#123;
private int m_nId = 0;
private int m_nParentId = 0;
private String m_sName = null;
private String m_sDescription = null;
private CompositeModel m_parent = null;
private Set m_children = null;

public int getId&#40;&#41; &#123;
return m_nId;
&#125;

public void setId&#40;int m_nId&#41; &#123;
this.m_nId = m_nId;
&#125;

public int getParentId&#40;&#41; &#123;
return m_nParentId;
&#125;

public void setParentId&#40;int m_nParentId&#41; &#123;
this.m_nParentId = m_nParentId;
&#125;

public String getName&#40;&#41; &#123;
return m_sName;
&#125;

public void setName&#40;String m_sName&#41; &#123;
this.m_sName = m_sName;
&#125;

public String getDescription&#40;&#41; &#123;
return m_sDescription;
&#125;

public void setDescription&#40;String m_sDescription&#41; &#123;
this.m_sDescription = m_sDescription;
&#125;

public CompositeModel getParent&#40;&#41; &#123;
return m_parent;
&#125;

public void setParent&#40;CompositeModel m_parent&#41; &#123;
this.m_parent = m_parent;
&#125;

public Set getChildren&#40;&#41; &#123;
return m_children;
&#125;

public void setChildren&#40;Set m_children&#41; &#123;
this.m_children = m_children;
&#125;

public String toString&#40;&#41; &#123;
final StringBuffer buf = new StringBuffer&#40;&#41;;
buf.append&#40;"CompositeModel"&#41;;
buf.append&#40;"\n\tm_nId="&#41;.append&#40;m_nId&#41;;
buf.append&#40;"\n\tm_nParent="&#41;.append&#40;m_nParentId&#41;;
buf.append&#40;"\n\tm_sName="&#41;.append&#40;m_sName&#41;;
buf.append&#40;"\n\tm_sDescription="&#41;.append&#40;m_sDescription&#41;;
buf.append&#40;"\n\tm_parent="&#41;.append&#40;m_parent == null ? null &#58; m_parent.toString&#40;&#41;&#41;;

Set children = getChildren&#40;&#41;;
if &#40;children == null&#41;
buf.append&#40;"\n\tHas no children"&#41;;
else &#123;
buf.append&#40;"\n\tNumber of children = " + children.size&#40;&#41;&#41;;
buf.append&#40;"\n\t&#123;"&#41;;
for &#40;Iterator i = children.iterator&#40;&#41;; i.hasNext&#40;&#41;;&#41; &#123;
CompositeModel com = &#40;CompositeModel&#41; i.next&#40;&#41;;
buf.append&#40;com.toString&#40;&#41;&#41;;
&#125;
buf.append&#40;"\n\t&#125;"&#41;;
&#125;

buf.append&#40;"\n\t------------------"&#41;;
return buf.toString&#40;&#41;;
&#125;
&#125;



---------CompositePM---------------
package example.framework.persistent;

import example.framework.model.CompositeModel;
import org.springframework.dao.DataAccessException;

import java.util.List;

public interface CompositePM &#123;
public List listComposite&#40;&#41;;
public CompositeModel findComposite&#40;int nId&#41;;
public void storeComposite&#40;CompositeModel composite&#41; throws DataAccessException;
public void updateComposite&#40;CompositeModel composite&#41; throws DataAccessException;
public void deleteComposite&#40;CompositeModel composite&#41; throws DataAccessException;
&#125;


------CompositePMImpl---------------
package example.framework.persistent;

import example.framework.model.CompositeModel;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate.support.Hibernat eDaoSupport;

import java.util.List;

public class CompositePMImpl extends HibernateDaoSupport implements CompositePM &#123;
public List listComposite&#40;&#41; &#123;
return getHibernateTemplate&#40;&#41;.find&#40;"from CompositeModel AS composite"&#41;;
&#125;

public CompositeModel findComposite&#40;int nId&#41; &#123;
return &#40;CompositeModel&#41; getHibernateTemplate&#40;&#41;.load&#40;CompositeModel.class, new Integer&#40;nId&#41;&#41;;
&#125;

public void storeComposite&#40;CompositeModel composite&#41; throws DataAccessException &#123;
getHibernateTemplate&#40;&#41;.save&#40;composite&#41;;
throw new DataAccessException&#40;"exception"&#41; &#123;&#125;;
&#125;

public void updateComposite&#40;CompositeModel composite&#41; throws DataAccessException &#123;
getHibernateTemplate&#40;&#41;.update&#40;composite&#41;;
&#125;

public void deleteComposite&#40;CompositeModel composite&#41; throws DataAccessException &#123;
getHibernateTemplate&#40;&#41;.delete&#40;composite&#41;;
&#125;
&#125;



package example.framework;

import example.framework.model.CompositeModel;
import example.framework.persistent.CompositePM;
import net.sf.hibernate.HibernateException;
import org.springframework.context.support.ClassPathXmlAp plicationContext;

import java.util.ArrayList;
import java.util.List;

public class TestFramework &#123;

private ClassPathXmlApplicationContext ac = null;
private CompositePM composite = null;

public void initFramework&#40;&#41; &#123;
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext&#40;"applicationContext.xml"&#41;;
composite = &#40;CompositePM&#41; ac.getBean&#40;"compositeTarget"&#41;;
&#125;

private void printComposite&#40;CompositeModel composite&#41; &#123;
System.out.println&#40;composite&#41;;
&#125;

private void printComposite&#40;List composites&#41; &#123;
for &#40;int i=0; i<composites.size&#40;&#41;; i++&#41;
printComposite&#40;&#40;CompositeModel&#41; composites.get&#40;i&#41;&#41;;
&#125;

public List listAllComposite&#40;&#41; &#123;
return composite.listComposite&#40;&#41;;
&#125;

public CompositeModel findComposite&#40;int nId&#41; &#123;
return composite.findComposite&#40;nId&#41;;
&#125;

public void insertComposite&#40;CompositeModel composite&#41; throws HibernateException &#123;
this.composite.storeComposite&#40;composite&#41;;
&#125;

public void performTest&#40;&#41; throws HibernateException &#123;
// select composite
List list = new ArrayList&#40;&#41;;
CompositeModel com = findComposite&#40;1&#41;;
list.add&#40;com&#41;;
printComposite&#40;list&#41;;

CompositeModel c = null;
// insert successfully
c = new CompositeModel&#40;&#41;;
c.setId&#40;10&#41;;
c.setParentId&#40;2&#41;;
c.setName&#40;"new composite"&#41;;
c.setDescription&#40;"Description"&#41;;
composite.storeComposite&#40;c&#41;;
&#125;

public static void main&#40;String&#91;&#93; agrs&#41; throws HibernateException &#123;
TestFramework tf = new TestFramework&#40;&#41;;

tf.initFramework&#40;&#41;;
tf.performTest&#40;&#41;;
&#125;
&#125;

Alef Arendsen
Dec 6th, 2004, 04:29 AM
It seems you're retrieving the target instead of the proxy here:



composite = &#40;CompositePM&#41; ac.getBean&#40;"compositeTarget"&#41;;


Change this to



composite = &#40;CompositePM&#41; ac.getBean&#40;"proxy"&#41;;


and you should be just fine...

regards,
Alef