现在的位置: 首页 > 综合 > 正文

Spring的事务管理与回滚

2014年09月05日 ⁄ 综合 ⁄ 共 3479字 ⁄ 字号 评论关闭

        最近在做项目的时候,才发现对Spring的事务是那么不了解,因此花了一些时间总结了一下自己对Spring的事务的理解。

      Spring、EJB的声明式事务默认情况下都是在抛出unchecked
exception并且这异常是RuntimeException或它的子类
后才会触发事务的回滚。

在测试项目写了一个dao,向mysql数据库插入数据,

下面分几种情况总结下:

第一种:程序运行出错,但没有异常 try{}catch 

public void  add() {

TUser user=new TUser();
user.setPassword("1234");
user.setUsername("lin");
user.setCreatetime(new Date());
this.getHibernateTemplate().save(user);
int i=1/0;//抛出异常
}

配置文件:

<bean id="baseLocalTxProxy" abstract="true"
		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<property name="transactionManager"
			ref="localTransactionManager" />
		<property name="transactionAttributes">
			<props>
				<prop key="*">PROPAGATION_REQUIRED</prop>
			</props>
		</property>
	</bean>
	<bean id="testDao"  parent="baseLocalTxProxy">
		<property name="target">
		<bean class="com.wyu.dao.TestDao">
		<property name="hibernateTemplate" ref="hibernateTemplate"></property>
		</bean>
		</property>
	</bean>

测试结果:事务回滚,没有向数据库插入数据。


第二种:程序运行错误,但有把异常try{}catch

public void  add() {
try {
TUser user=new TUser();
user.setPassword("1234");
user.setUsername("lin");
user.setCreatetime(new Date());
this.getHibernateTemplate().save(user);
int i=1/0;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();//抛出异常

}

}

ps:配置文件没有改

测试结果:事务回滚,没有向数据库插入数据。


第三种:程序运行出错,有把异常try{}catch,但抛出异常不是RuntimeException或它的子类

public void  add() throws  ClassNotFoundException {
try {
TUser user=new TUser();
user.setPassword("1234");
user.setUsername("lin");
user.setCreatetime(new Date());
this.getHibernateTemplate().save(user);
int i=1/0;
} catch (Exception e) {
e.printStackTrace();
throw new  ClassNotFoundException();//抛出异常

}

}

ps:配置文件没有改

测试结果:事务不回滚,向数据库插入数据。

第四种:程序运行出错,有把异常try{}catch,但抛出异常不是RuntimeException或它的子类,在配置文件增加指定会回滚的异常类

public
void  add() throws  ClassNotFoundException {

try {
TUser user=new TUser();
user.setPassword("1234");
user.setUsername("lin");
user.setCreatetime(new Date());
this.getHibernateTemplate().save(user);
int i=1/0;
} catch (Exception e) {
e.printStackTrace();
throw new  ClassNotFoundException();//抛出异常

}

}

配置文件修改为:

<bean
id="baseLocalTxProxy" abstract="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"
ref="localTransactionManager" />
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED,-ClassNotFoundException</prop>
</props>
</property>
</bean>
<bean id="testDao"  parent="baseLocalTxProxy">
<property name="target">
<bean class="com.wyu.dao.TestDao">
<property name="hibernateTemplate" ref="hibernateTemplate"></property>
</bean>
</property>
</bean>

测试结果:事务回滚,没有向数据库插入数据。


总结:

1、Propagation (事务的传播属性)

PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。

1: PROPAGATION_REQUIRED
加入当前正要执行的事务不在另外一个事务里,那么就起一个新的事务
比如说,ServiceB.methodB的事务级别定义为PROPAGATION_REQUIRED, 那么由于执行ServiceA.methodA的时候,
ServiceA.methodA已经起了事务,这时调用ServiceB.methodB,ServiceB.methodB看到自己已经运行在ServiceA.methodA
的事务内部,就不再起新的事务。而假如ServiceA.methodA运行的时候发现自己没有在事务中,他就会为自己分配一个事务。
这样,在ServiceA.methodA或者在ServiceB.methodB内的任何地方出现异常,事务都会被回滚。即使ServiceB.methodB的事务已经被
提交,但是ServiceA.methodA在接下来fail要回滚,ServiceB.methodB也要回滚


2、spring的事务边界是在调用业务方法之前开始的,业务方法执行完毕之后来执行commit or
rollback(Spring默认取决于是否抛出runtime异常). 


3、在调用业务方法抛出异常,并把它catch到并且没有向外抛异常,则==生吞掉异常 ,对于抛出的异常不是RuntimeException或它的子类,事务不会回滚的。

4、在调用业务方法抛出异常,这异常不是RuntimeException或它的子类,并把catch异常并向外抛,如果在事务传播配置加上指定会回滚的异常,则事务会回滚的。

5、在调用业务方法抛出异常,如果在事务传播配置加上指定会回滚的异常(不是RuntimeException或它的子类),对于发生的异常是RuntimeException或它的子类,则事务也会回滚的。


抱歉!评论已关闭.