Spring的事务管理和Aop

        事务和aop也是面试和Spring代码开发中老生常谈的问题,对于这块,我自己的感觉是都能说出是干嘛的也能写出东西,但是详细的深入的了解,和他们之间的关系其实不是很清楚。每次有人问aop能干嘛时,一般就直接说哥,可以完成事务,或者拦截器等有关面向切面的功能,一般也就结了。但是,这是不好的,在这里想总结一下,事务管理和aop之间的联系,同时主要说下Spring事务管理的问题。

     事务管理

         我们在实际业务场景中,经常会遇到数据频繁修改读取的问题。在同一时刻,不同的业务逻辑对同一个表数据进行修改,这种冲突很可能造成数据不可挽回的错乱,所以我们需要用事务来对数据进行管理。事务必须服从ACID原则。ACID指的是原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)。
通俗理解,事务其实就是一系列指令的集合。

      AOP:

         即面向切面编程,利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事务。

        可以想到,因为aop面向切面的特性,在某些dao或者service执行时,可以该方法之前和之后,加入事务管理有关代码其。来实现一个面向切面的事务管理。也就是aop可以帮助实现事务管理,但不是所有的事务管理都是AOP实现的。

          其实对于事务管理主要分成两种声明类型,分别是 

编程式事务:所谓编程式事务指的是通过编码方式实现事务,即类似于JDBC编程实现事务管理。管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。

声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。

       显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。

声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。

    关于编程式事务和声明式事务的代码案例,这篇博文我是赞同的。

http://blog.csdn.net/liaohaojian/article/details/70139151。反而很多高票的其他博客讲解代码是对的,但是意义是错的,这两种事务的区别主要是如我说的意义区分,而不是用了注解就怎么怎么样了。

    咱们继续讲讲事务,事务的还有个问题就是,新手很容易犯的一个错误就是,以为只要引用了事务就万事大吉了,其实是不太了解原理,这里面还有一层问题就是,事务的调起机制。

    事务的回滚与不回滚

      先上结论,事务在不配置的情况下默认只有:

  • unchecked异常,
即RuntimeException(运行时异常),即不需要try...catch...或throws 机制去处理的异常才会回滚。

   除了unchecked异常,其他继承自java.lang.Exception得异常统称为Checked Exception,是不会回滚的。比如说,SQLException, TimeoutException这类的异常。编译的时候也会要求你try-catch住。这种情况啊报错,srping默认为你会自己在catch中对异常进行处理,所以他就不会帮你回滚了。这个我觉得逻辑上也是说得通的。那我们想要对这些异常也回滚怎么办呢,很多种方式,我说几种:

1.注解情况下用@Transactional(rollbackFor = { Exception.class }) ,手动设置rollback错误类型

2.catch后 throw new RuntimeException 让事务回滚; 让cath抛出runtimeException异常

3.如果是用编程式在内部写代码的形式也可以在catch中手动调用rollback

  1. public void testdelivery(){  
  2.         //定义事务隔离级别,传播行为,  
  3.         DefaultTransactionDefinition def = new DefaultTransactionDefinition();    
  4.         def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);    
  5.         def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);    
  6.         //事务状态类,通过PlatformTransactionManager的getTransaction方法根据事务定义获取;获取事务状态后,Spring根据传播行为来决定如何开启事务  
  7.         TransactionStatus status = txManager.getTransaction(def);    
  8.         jdbcTemplate = new JdbcTemplate(dataSource);  
  9.         int i = jdbcTemplate.queryForInt(COUNT_SQL);    
  10.         System.out.println("表中记录总数:"+i);  
  11.         try {    
  12.             jdbcTemplate.update(INSERT_SQL, "1");    
  13.             txManager.commit(status);  //提交status中绑定的事务  
  14.         } catch (RuntimeException e) {    
  15.             txManager.rollback(status);  //回滚  
  16.         }    
  17.         i = jdbcTemplate.queryForInt(COUNT_SQL);    
  18.         System.out.println("表中记录总数:"+i);  
  19.     }  

我感觉应该是很清楚了。有啥补充,我后期再加上吧!开心~


猜你喜欢

转载自blog.csdn.net/zxysshgood/article/details/79088099