1.xxx-servlet.xml配置
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
com.mysql.jdbc.Driver
jdbc:mysql://localhost:3306/test
root
111111
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
net.spring.model
org.hibernate.dialect.MySQLDialect
true
true
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
2.调用
方法1:
TestServiceImpl
@Override
@Transactional
public void upd(){
testDao.upd(); //调用一个dao的方法
}
TestDaoImpl
@Override
public void upd(){
SQLQuery sqlQuery = this.getSession().createSQLQuery("update user set name='1111' where id='4'");
sqlQuery.executeUpdate();
throw new RuntimeException();//这里抛出异常,上面的更新操作就会回滚
//注意,如果调用的更新或者删除操作是一个存储过程,那么即便抛出了异常,也不会回滚了
//SQLQuery sqlQuery = this.getSession().createSQLQuery("{call updUser(?)}");
//sqlQuery.setInteger(0, 4);
//sqlQuery.executeUpdate();
//throw new RuntimeException();//因为调用的是一个存储过程,所以不会回滚了。
}
方法2:
TestServiceImpl
@Override
@Transactional
public void upd(){
testDao.upd(); // 第一个方法正确
testDao.upd2();//第二个方法抛异常,然后回滚
}
TestDaoImpl
@Override
public void upd(){
SQLQuery sqlQuery = this.getSession().createSQLQuery("update user set name='1111' where id='4'");
sqlQuery.executeUpdate();
}
@Override
public void upd2(){
throw new RuntimeException();
}
注:
将异常捕获,并且在catch块中不对事务做显式提交(或其他应该做的操作如关闭资源等)=生吞掉异常;
spring的事务边界是在调用业务方法之前开始的,业务方法执行完毕之后来执行commit or rollback(Spring默认取决于是否抛出runtime异常).
如果抛出runtime exception 并在你的业务方法中没有catch到的话,事务会回滚。
一般不需要在业务方法中catch异常,如果非要catch,在做完你想做的工作后(比如关闭文件等)一定要抛出runtime exception,否则spring会将你的操作commit,这样就会产生脏数据.所以你的catch代码是画蛇添足。
由此可以推知,在spring中如果某个业务方法被一个
try {
//bisiness logic code
} catch(Exception e) {
//handle the exception
整个包裹起来,则这个业务方法也就等于脱离了spring事务的管理,因为没有任何异常会从业务方法中抛出!全被捕获并吞掉,导致spring异常抛出触发事务回滚策略失效。