免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 857 | 回复: 0
打印 上一主题 下一主题

spring事务探索 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-10-27 18:37 |只看该作者 |倒序浏览

spring自建事务管理模块。而且这个事务管理是一个抽象设计,可以应用到很多场合,包括普通的DataSource,jta,jms和hibernate上。
要正确使用spring的事务,首先需要了解spring在事务设计上的一些概念
统观spring事务,围绕着两个核心PlatformTransactionManager和TransactionStatus
PlatformTransactionManager直译过来就是平台相关事务,这里的平台指的是“事务源”,包括刚才我说的DataSource,jta等等。这些无一不是一个事务源。广义的说,凡是可以完成事务性操作的对象,都可以设计出相对应的PlatformTransactionManager,只要这个事务源支持commit,rollback和getTransaction语意。
查看spring代码,可以发现这些manager实现事务,就是调用事务源的事务操作方法
比如
HibernateTransactionManager
代码
protected void doCommit(DefaultTransactionStatus status) {   
        HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();   
        if (status.isDebug()) {   
            logger.debug("Committing Hibernate transaction on session [" +   
                    txObject.getSessionHolder().getSession() + "]");   
        }   
        try {   
            txObject.getSessionHolder().getTransaction().commit();   
        }   
...   
  
    }  
jdbc 的DataSourceTransactionManager
代码
protected void doCommit(DefaultTransactionStatus status) {   
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();   
        Connection con = txObject.getConnectionHolder().getConnection();   
        if (status.isDebug()) {   
            logger.debug("Committing JDBC transaction on connection [" + con + "]");   
        }   
        try {   
            con.commit();   
        }   
        ...   
    }  
那么PlatformTransactionManager以什么依据处理事务呢?
是TransactionStatus
查看api发现这个接口有三个方法
isNewTransaction() ,isRollbackOnly(),setRollbackOnly()
PlatformTransactionManager就是根据前两个方法决定是否要创建一个新事务,是要递交还是回滚。至于第三个方法是改变事务当前状态的,很多地方都要用到,偏偏PlatformTransactionManager自身好像不怎么用,毕竟事务状态的改变是由程序员代码决定的,不需要一个manager多管闲事。
总结上面所说的,spring的事务由PlatformTransactionManager管理,manager最后调用事务源的方法来实现一个事务过程。而manager通过TransactionStatus 来决定如何实现。
接下去说spring事务中的TransactionTemplate和TransactionInterceptor
TransactionTemplate其实和spring中其他的template的作用类似,起到化简代码的作用,不要被它那么长的名字吓倒了,事实上这个template并不是什么非常核心的对象。如果比较学究派的,可以去看看template设计模式,在此就不再对此赘述了。
为什么要有TransactionTemplate?先来看看如果没有TransactionTemplate,我们的代码该怎么写
先来看看spring reference中的一段代码
代码
DefaultTransactionDefinition def = new DefaultTransactionDefinition()   
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);   
  
TransactionStatus status = transactionManager.getTransaction(def);   
  
try {   
    // execute your business logic here   
} catch (MyException ex) {   
    transactionManager.rollback(status);   
    throw ex;   
}   
transactionManager.commit(status);  
这是直接使用transactionManager的例子,可以看到真正执行business logic 的地方是在try当中那段,前后的代码都是为了完成事务管理的。如果每个business logic都要写上那么一段,我肯定是疯了。我们翻出TransactionTemplate的代码看看他怎么化简了我们的代码
代码
public Object execute(TransactionCallback action) throws TransactionException {   
        TransactionStatus status = this.transactionManager.getTransaction(this);   
        Object result = null;   
        try {   
            result = action.doInTransaction(status);   
        }   
        catch (RuntimeException ex) {   
            // transactional code threw application exception -> rollback   
            rollbackOnException(status, ex);   
            throw ex;   
        }   
        catch (Error err) {   
            // transactional code threw error -> rollback   
            rollbackOnException(status, err);   
            throw err;   
        }   
        this.transactionManager.commit(status);   
        return result;   
    }  
同上面的代码如出一辙,前后是事务处理代码,当中那段result = action.doInTransaction(status);是我们的应用代码。至于action是什么,全看各位的需要了。但是有一点要主要,如果利用TransactionTemplate,那么他不管你扔出什么异常都会回滚事务,但是回滚的是哪个事务呢?继续挖代码
代码
private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException {   
        if (logger.isDebugEnabled()) {   
            logger.debug("Initiating transaction rollback on application exception", ex);   
        }   
        try {   
            this.transactionManager.rollback(status);   
        }   
        catch (RuntimeException ex2) {   
            logger.error("Application exception overridden by rollback exception", ex);   
            throw ex2;   
        }   
        catch (Error err) {   
            logger.error("Application exception overridden by rollback error", ex);   
            throw err;   
        }   
    }  
真相大白,是对template所持有的某个transactionManager进行回滚。所以如果你的应用代码用的是事务源a的一些资源,比如到服务器a的一个datasource,但是你的transactionManager管理的是另一些资源,比如服务器b的一个datasource,代码铁定不会正常运行
特别是在一些多事务源的程序里,这点千万不能搞错。如果多个事务源之间要完成全局事务,还是老老实实用分布式事务管理服务吧(jta)
那么TransactionInterceptor是干什么的?这个是spring 的声明式事务的支持方式。因为用TransactionTemplate要硬编码,而且调整事务策略很麻烦(不是说不能调。举个例子原来程序抛出异常A需要回滚,现在不需要要,我就可以把a catch吃掉。这时候template就不会回滚了。但是每次调整都要重写编码。)而用TransactionInterceptor就可以将这些调整写在配置中。我们再来挖TransactionInterceptor的代码
代码
public Object invoke(MethodInvocation invocation) throws Throwable {   
        // Work out the target class: may be null.   
        // The TransactionAttributeSource should be passed the target class   
        // as well as the method, which may be from an interface   
        Class targetClass = (invocation.getThis() != null) ? invocation.getThis().getClass() : null;   
           
        // Create transaction if necessary   
        TransactionInfo txInfo = createTransactionIfNecessary(invocation.getMethod(), targetClass);   
  
        Object retVal = null;   
        try {   
            // This is an around advice.   
            // Invoke the next interceptor in the chain.   
            // This will normally result in a target object being invoked.   
            retVal = invocation.proceed();   
        }   
        catch (Throwable ex) {   
            // target invocation exception   
            doCloseTransactionAfterThrowing(txInfo, ex);   
            throw ex;   
        }   
        finally {   
            doFinally(txInfo);   
        }   
        doCommitTransactionAfterReturning(txInfo);   
  
        return retVal;   
    }  
万变不离其宗。
所以使用spring的事务管理需要作这些事
1,设置好事务源,比如DataSource,hibernate的session。如果有多个事务源要考虑他们之间是否有全局事务,如果有,老老实实用jta,否则就需要自己写一个manager了
2,设置manager,根据你的事务源选择对应的PlatformTransactionManager
3,选择实现事物的方式,用template还是interceptor。用template代码直观点,但是template所管辖的manager和你应用代码所用的事务源要一致。如果用interceptor千万注意,一定要调用interceptor那个bean,而不是原始的那个target。在坛子上我已经看到至少有两个朋友说spring事物不起作用,从配置和代码上看都正确,这时要好好查查,调用的bean是哪一个。
4,这个是设计问题了,推荐事务处于一个较高层次,比如service上的某个函数,而底层的dao可以不考虑事务,否则可能会出现事务嵌套,增加程序复杂度。


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/50183/showart_409013.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP