从源码理解spring事务(1)

来源:互联网 发布:python xpath 编辑:程序博客网 时间:2024/06/03 23:49

         在介绍spring事务之前,首先弄清楚什么是事务。事务是访问数据库中各种数据项的一个程序执行单元,他满足ACID的特性,事务是恢复和并发控制的基本单位。那么什么又是spring事务?spring事务能够做哪些事?使用spring事务的好处是什么?

         众所周知,Spring是一块主板和粘合剂,spring中也定义了一个整体的,与spring其他组件无缝衔接的事务基础,具体来说,PlatformTransactionManager就是一个能够适用各种事务和数据源的接口,接口定义如下。通过这个接口,spring不仅能够操作JDBC的事务,同时也能够操作诸如hibernate,JTA等事务类型。带来的好处是显而易见的,首先是统一的实现,无缝的衔接,真正的高内聚低耦合的设计;其次,简化了丑陋的try-catch-finally的普通事务写法,通过这部分的封装,降低了编码的难度;再次,通过声明式事务编程,实现了可配置的事务管理。

public interface PlatformTransactionManager {TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;void commit(TransactionStatus status) throws TransactionException;void rollback(TransactionStatus status) throws TransactionException;}

         从UML图可以看出,跟PlatformTransactionManager相关的核心接口有TransactionStatus以及TransactionDefinition(可以看到spring把面向接口编程贯彻得非常好)


         在开始之前,我们首先来回顾一下不使用任何框架时我们是如何去操纵JDBC并且完成事务过程的。可以看到,在代码段transaction1中,我们首先要把自动提交设置为false,然后在try块中做我们带事务的的业务逻辑,在catch块中回滚,并且在finally块中释放资源。

public void transaction1() throws Exception {Connection conn = MysqlDatasource.getConnection();conn.setAutoCommit(false);try {// doSomeThing();conn.commit();} catch (Exception e) {conn.rollback();} finally {try{conn.close();}catch(Exception e){//error process}}}

           我们来看一个重要的问题,要想在spring中控制其他事务源的事务,他需要做什么,见下面代码段transaction2。如前面提到的,spring提供了PlatformTransactionManager来抽象具体事务策略,从而通过抽象的transactionManager来代理具体的事务控制,transaction2其实非常类似transaction1,不同的是,它被抽象了,这个transactionManager可以代理transaction1中的Connection。从这里我们可以很好的学习到spring是如何去充当一个总理或者一块主板功能的,奥秘就是一个高级的抽象。由于PlatformTransactionManager是一个接口,可以想象,凡是遵循该接口定义的事务实现策略都可以被粘合到spring中,所以你可以看到JtaTransactionManager,DataSourceTransactionManager, JdoTransactionManager, HibernateTransactionManager等都是spring中能够支持的事务策略类。

public void transaction2() throws Exception {TransactionDefinition def = new DefaultTransactionDefinition();TransactionStatus status = transactionManager.getTransaction(def);try {// doSomeThing();transactionManager.commit(status);} catch (Exception e) {transactionManager.rollback(status);}// return result object}

           上面这段程序或许你并不觉得烦琐,但是要知道,在一个企业级系统中,可能有成千上万个这样有待事务控制的方法,将上面这段程序重复1000次?我想我们都会汗颜。

           我们来看看spring是如何简化我们的工作。Spring事务的初衷就是砍掉这部分多余的代码,在这个例子中,除了doSomeThingA(),doSomeThingB()这两段业务逻辑代码,其余都是多余的。为了达到这个目的,编程式事务的帮助类TransactionTemplate采用了回调去执行业务逻辑,关键代码如下。可以看出,我们只需要把真正需要做事务的业务逻辑包装在doInTransaction中就行了。

public void myBusiness(){transactionTemplate.execute( new TransactionCallback<Object>(){        public Object doInTransaction(TransactionStatus ts){ //do sth        return "";        }    });}

            而这个回调的业务逻辑事实上正是被包在了类似transaction2的程序中,见如下spring源码之TransactionTemplate,事实上,回调是spring中大量使用的技巧(据说win32编程没其他更多技巧,唯回调而已),使用了TransactionTemplate的代码更加简洁,bug更少,可维护性更好,而且可以使用platformTransactionManager的模拟对象测试而无需JTA环境,因此更易于测试。

public <T> T execute(TransactionCallback<T> action) throws TransactionException {if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);}else {TransactionStatus status = this.transactionManager.getTransaction(this);T result;try {result = action.doInTransaction(status);}catch (RuntimeException ex) {// Transactional code threw application exception -> rollbackrollbackOnException(status, ex);throw ex;}catch (Error err) {// Transactional code threw error -> rollbackrollbackOnException(status, err);throw err;}catch (Exception ex) {// Transactional code threw unexpected exception -> rollbackrollbackOnException(status, ex);throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");}this.transactionManager.commit(status);return result;}}

            很快就会有人提出问题了,回调是一种简化代码比较好的方式,但是调用回调的匿名方法并不够优雅,看起来声明式事务管理是更优雅的方式,因为我们终于可以不用在代码段看见事务相关的代码了,我们彻底解放了。

            待续……


参考文档:

事务定义http://baike.baidu.com/view/121511.htm

Spring事务原理 http://www.blogjava.net/dragonofson/articles/54690.html

Spring开发之事务管理http://tech.ccidnet.com/art/3539/20060323/487865_1.html