首页 > 代码库 > 事务学习笔记二
事务学习笔记二
通过Spring的事务管理框架,我们可以按照统一的编程模型来进行事务编程,不用关心数据访问技术以及具体访问什么类型的事务资源。再结合Spring的AOP框架,事务框架为我们带来了声明式事务。整个Spring的事务管理框架的设计原则是:让事务管理的关注点与数据访问的关注点相分离。在具体使用过程中:
A)业务层使用事务的抽象API进行事务界定,不需要关心事务资源是什么,由框架实现类来管理
B)数据访问层只关心数据访问API,不关心数据资源是否参加事务,有框架类来管理
我们使用事务框架的基本流程是:
public class FooService {
private PlatformTransactionManager tm;
public void serviceMethod() {
TransactionDefinition td = …?;
TransactionStatus ts =tm.getTransaction(td);
try {
// dao1.doDataAccess();
// dao2.doDataAccess();
}
catch(DataAccessException e) {
tm.rollback(ts);
throw e;
}
tm.commit(ts);
}
有了这个统一的事务管理编程模型,不管数据访问方式如何变换,事务管理实现可以岿然不动,至于声明式事务管理,也就是自然而然的事情了。
在知道了我们使用事务框架的基本使用流程后,我们来分析一下如何该框架的实现原理。首先看事务界定的核心接口:
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition d) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void roolback(TransactionStatus status) throws TransactionException;
}
这是一个顶层接口,具体的事务界定策略由具体的实现类执行,针对不同的数据访问方式,Spring提供了相应的实现类。其次,我们以JDBC数据访问方式为例来实现一个具体的事务界定策略。对于层次划分清晰的应用来说,我们将事务管理放在Service层,将数据访问逻辑放在DAO层。JDBC的局部事务由同一个Connection来完成,为了保证两个DAO的数据访问方法处于同一事物中,我们通常使用connection-passing的方式,但是此方式没有很好地隔离事务管理代码与数据访问代码,并且使得DAO方法对具体的Connection类型产生依赖。经过思考,我们决定不在Service层与DAO层之间直接传递Connection,而是把整个事务对应的Connection实例存放到一个统一的地方去,无论是谁,需要使用时再从这个统一的地方获取,这样就很好地接触了事务管理代码与数据访问代码之间的直接耦合。
假如用来统一存放Connection的容器是TransactionResourceManager,那么该容器类的主要结构如下:
public class TransactionResourceManager {
private static ThreadLocal resource = new ThreadLocal();
public static Object getResource() {
return resource.get();
}
public static void bindResource(Object resource) {
resources.set(resource);
}
public static Object unbindResource() {
Object res = getResource();
resource.set(null);
return res;
}
}
可以看到,该容器类使用了ThreadLocal类来保存线程本地变量。我们的具体事务界定策略实现只需要在事务开始的时候,通过容器方法把Connection绑定到线程,然后在事务结束的时候解除绑定即可。为了在DAO层的数据访问时保证使用的是同一个Connection对象,我们的DAO层方法必须使用TransactionResourceManager来获取数据库连接并进行数据访问。经过前面一个步骤的努力,现在进行事务控制的时候,我们只需要为Service对象提供相应的PlatformTransactionManager实现类即可。但是,路上的事务管理框架依然存在如下两个主要问题:
A)如何保证PlatformTransactionManager的相应方法的调用顺序?
B)如何去除强制每个数据访问对象使用TransactionResourceManager来获取数据资源接口?
实际上,我们使用DataSourceUtils工具类来管理Connection,该类会从类似于TransactionResourceManager的类那里获取Connection资源。如果当前线程之前没有绑定任何Connection,那么使用数据访问对象的DataSource引用获取新的Connection,否则,使用绑定的那个connection。所以,在使用Spring事务管理框架时,必须通过DataSourceUtils来获取连接,而且像JdbcTemplate等类内部已经使用DataSourceUtils来管理链接了。从这里我们可以看到,Spring的事务管理与它的数据访问框架是紧密结合的。
事务学习笔记二