我正在使用spring 3.0.5和hibernate 3.6。在我的项目中有一种情况,我必须回滚抛出的任何异常的事务或发生错误。这个示例代码,Everything工作正常,但是当我抛出异常时事务没有被回滚但是如果抛出任何异常,例如 mysql.IntegrityConstraintException ,则事务被回滚,为什么这不会发生在我的情况?
的applicationContext.xml
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:database.properties"/>
</bean>
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="packagesToScan" value="com.alw.imps"/>
<property name="configLocation">
<value>
classpath:hibernate.cfg.xml
</value>
</property>
</bean>
<bean id="stateDao" class="com.alw.imps.dao.StateDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="stateService" class="com.alw.imps.services.StateService">
<property name="stateDao" ref="stateDao"></property>
<property name="cityDao" ref="cityDao"></property>
<property name="customerDao" ref="customerDao"></property>
</bean>
<bean id="customerDao" class="com.alw.imps.dao.CustomerDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="cityDao" class="com.alw.imps.dao.CityDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:advice id = "txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
服务类StateService
@Transactional(rollbackFor={Exception.class})
public class StateService {
private StateDaoImpl stateDao;
private CityDao cityDao;
private CustomerDao customerDao;
public void setCustomerDao(CustomerDao customerDao) {
this.customerDao = customerDao;
}
public void setStateDao(StateDaoImpl stateDao) {
this.stateDao = stateDao;
}
public CityDao getCityDao() {
return cityDao;
}
public void setCityDao(CityDao cityDao) {
this.cityDao = cityDao;
}
public void addState() {
try {
State state=new State();
state.setStateName("Delhi");
stateDao.create(state);
addCity();
addCustomer();
} catch(Exception e) {
e.printStackTrace();
}
}
public void addCity() throws Exception {
City city=new City();
city.setCiytName("Delhi");
city.setStateId(1);
cityDao.create(city);
}
public void addCustomer() throws Exception {
throw new java.lang.Exception();
}
DAO
public class StateDaoImpl extends GenericDaoImpl<State, Integer> implements StateDao {
}
GenericDaoImpl
public class GenericDaoImpl<T,PK extends Serializable> implements GenericDao<T,PK> {
public SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session getSession() {
return sessionFactory.getCurrentSession();
}
public PK create(T o) {
Session ss= getSession();
ss.save(o);
return null;
}
hibernate.cfg
<hibernate-configuration>
<session-factory>
<property name="connection.pool_size">1</property>
<property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">update</property>
<property name="defaultAutoCommit">false</property>
<mapping class="com.alw.imps.pojo.State"/>
<mapping class="com.alw.imps.pojo.City"/>
</session-factory>
</hibernate-configuration>
因为我说我的问题是当我从方法 addCustomer()
中抛出类型异常的异常时,事务没有得到回滚答案 0 :(得分:12)
您的事务未回滚,因为没有抛出异常:您调用的addState()
方法捕获异常:
public void addState() {
try {
State state=new State();
state.setStateName("Delhi");
stateDao.create(state);
addCity();
addCustomer();
}
catch(Exception e) {
e.printStackTrace();
}
}
因此,事务性Spring代理不会看到任何抛出的异常,也不会回滚事务。
它适用于从DAO抛出的异常,因为DAO本身是事务性的,因此它自己的事务代理检测DAO抛出的异常并标记事务以进行回滚。然后将异常传播到服务并由您的代码捕获,但此时事务已标记为回滚。
答案 1 :(得分:4)
您的事务没有回滚,因为您没有让Exception访问Spring框架,您正在捕获代码本身的异常。 而不是
public void addState()
{
try
{
State state=new State();
state.setStateName("Delhi");
stateDao.create(state);
addCity();
addCustomer();
}
catch(Exception e)
{
e.printStackTrace();
}
}
使用
public void addState()
{
State state=new State();
state.setStateName("Delhi");
stateDao.create(state);
addCity();
addCustomer();
}
答案 2 :(得分:1)
事务尚未回滚,因为您正在通过编写catch块来捕获异常..
这可以在正常情况下完成,但是在spring事务中,如果你这样做,spring transaction manager如何知道异常发生...这就是为什么它不会被回滚。
答案 3 :(得分:0)
您可以在Spring API doc中找到大多数问题的答案。
@Transactional
有一个字段Class<? extends Throwable>[] rollbackFor()
:
默认情况下,交易将在
RuntimeException
上回滚Error
但未检查异常(业务例外)。请参阅org.springframework.transaction.interceptor.DefaultTransactionAttribute.rollbackOn(Throwable)
以获取详细说明。
意味着,对于以下情况,无论调用者如何处理异常,只有第一个RunTimeException
情况会默认调用roleback。
// Only this case would roll back by default
@Override
@Transactional
public void testRollbackRuntimeException() {
// jpa operation.
throw new RuntimeException("test exception");
}
// never roll back, because its caught.
@Override
@Transactional
public void testRollbackRuntimeExceptionCaught() {
try {
throw new RuntimeException("test exception");
} catch(Exception e) {}
}
// @Transactional(rollbackFor = Exception.class) would also rollback. but by default no
@Override
@Transactional
public void testRollBackWithExceptionCaught() throws Exception {
throw new Exception("test exception");
}
// never roll back because the checked exception is caught.
@Override
@Transactional
public void testRollBackWithExceptionCaught() {
try {
throw new Exception("test exception");
} catch (Exception e) {}
}
大多数情况下,您可能希望使用以下方式回滚已检查的异常
@Transactional(rollbackFor = Exception.class)