标签:style blog http io ar color os 使用 sp
题目起的有些拗口了,简单说,这篇文章想要解释Spring为什么会选择使用ThreadLocal将资源和事务绑定到线程上,这背后有着什么样的起因和设计动机,通过分析帮助大家更清晰地认识Spring的线程绑定机制。本文原文链接:http://blog.csdn.net/bluishglc/article/details/7784502 转载请注明出处!
“原始”的数据访问写法
访问任何带有事务特性的资源系统,像数据库,都有着相同的特点:首先你需要获得一个访问资源的“管道”,对于数据库来说,这个所谓的“管道”是JDBC里的Connection,是Hibernate里的Session.然后你会通过“管道”下达一系列的读写指令,比如数据库的SQL,最后你会断开这个“管道”,释放对这个资源的连接。在Spring里,用访问资源的“管道”来指代资源,因此JDBC的Connection和Hibernate的Session都被称之为“资源”(Resource)(本文会交替使用这两种称呼)。另一方面,资源与事务又有着紧密的关系,事务的开启与提交都是在某个“Resource”上进行的。以Hibernate为例,一种“原始”的数据访问程序往往会写成这样:
Session session = sessionFactory.openSession();//获取“资源” Transaction tx = null; try { tx = session.beginTransaction(); //开始事务 .... DomainObject domainObject = session.load(...); //数据访问操作 .... domainObject.processSomeBusinessLogic();//业务逻辑计算 .... session.save(domainObject); //另一个数据访问操作 .... session.save(anotherDomainObject); //又一个数据访问操作 .... session.commit(); //提交事务 } catch (RuntimeException e) { tx.rollback(); throw e; } finally { session.close(); //释放资源 }
上述代码的思路很直白:首先获得数据库“资源”,然后在该资源上开始一个事务,经过一系列夹杂着业务计算和数据访问的操作之后,提交事务,释放资源。
分层带来的困扰
相信很多人一下就能看出上面代码的问题:业务逻辑与数据访问掺杂在了一起,犯了分层的“忌讳”。一个良好的分层系统往往是这样实现上述代码的:使用Service实现业务逻辑,使用DAO向Service提供数据访问支持。
某个Service的实现类:
某个DAO的Hibernate实现类:
public class MyDaoHibernateImpl implements MyDao { public void save(DomainObject domainObject){ //在这里获得资源并开启事务么?NO!你怎么确定这个方法一定是一个独立的事务 //而不会是某个事务的一部分呢?比如我们上面的Service。 //Session session = sessionFactory.openSession(); //session.beginTransaction(); .... session.save(domainObject); } .... }
矛盾的焦点
从“分层”的角度看,上述方案算是“完美”了,但却回避了一个现实的技术问题:如何安置“获取资源”(也就是session)和“开启事务”的代码呢?像代码中注释的那样,好像放在哪里都有问题,看上去像是一个“不可调和”的矛盾。如果要解决这个“不可调和”的矛盾,在技术上需要解决两个难题:
Spring的解决之道
Spring使用基于AOP的声明式事务定界解决了第一个问题,而使用基于ThreadLocal的资源与事务线程绑定成功地解决了第二个问题。(关于spring的具体实现,可以参考我的另一篇文章:Spring源码解析(一) Spring事务控制之Hibernate ,第一个问题所涉及源码主要是:
org.springframework.aop.framework.JdkDynamicAopProxy 和 org.springframework.transaction.interceptor.TransactionInterceptor
第二个问题所涉及源码主要是:
org.springframework.transaction.support.AbstractPlatformTransactionManager 和 org.springframework.transaction.support.TransactionSynchronizationManager)
本文我们重点关注Spring是如何解决第二个问题的,对于这个问题有两点需要特别地解释:
Hibernate自己动手丰衣足食
作为一小段插曲,我们聊聊Hibernate。大概是为满足对Session-Per-Transaction的普遍需求,Hibernate也实现了自己的Session-Per-Transaction模型,就是大家所熟知的SessionFactory.getCurrentSession(),该方法返回绑定在当前线程上session实例,若当前线程没有session实例,创建一个新的实例以ThreadLocal的形式绑定到当前线程上,同时,该方法生成的session其实是一个session代理,这个代理会对内部的实际session附加如下动作:
正是这两点确保了Session与Transaction保持了一致的生命周期。
一切是这样进行的
结合上述场景和Spring的解决方案,一个使用了Spring声明性事务,实现了良好分层的程序,它的资源和事务在Spring的控制下是这样工作的:
一个小小的总结
Spring基于ThreadLocal的“资源-事务”线程绑定设计的缘起
标签:style blog http io ar color os 使用 sp
原文地址:http://www.cnblogs.com/studies/p/4160749.html