1. 事务和线程
不论是JDBC还是Spring,在做事务处理的时候,都是和线程绑定的,可以猜想得到,事务的状态及其相关的变量都是存储在Thread对象的ThreadLocal中的。可以写一段代码来验证。
2. 分布式事务
那么如果要让事务来跨线程,需要怎么做呢?其实问题很简单,无论是跨线程还是跨进程,都需要一个共享区来存储事务相关的状态和变量,而且这个共享区是线程/进程之间共享的。那么,我们常说的分布式事务,它常采用的两段式提交,其核心思想就是在资源(数据库、文件等)管理器之上,抽象出一层事务管理器。资源提交是提交到事务管理器,我们称之为预交。事务管理器可以管理多个逻辑或者物理上分离的资源,所有资源提交的信息都由事务管理器来管理,通过资源管理器反馈的信息,事务管理器来决定是提交还是回滚。
3. 事务回滚
我们再发散一下,怎么实现事务回滚呢?假设你使用的是一个不支持事务的数据库,恰好有一个业务场景又需要事务,那么你需要怎么实现事务呢?事务提交可能比较好处理,比较简单的做法是,利用ThreadLocal来存储需要提交的SQL,当commit方法执行的时候,在按照顺序提交本线程的所有SQL给数据库来执行,存储结构使用队列(先进先出);那么,为了便于回滚操作,每当新增一条正想SQL,同时需要新增一个逆向操作,并且在ThreadLocal中维护,存储结构使用栈(后进先出),这样当rollback方法执行的时候,逆序回退即可。
4. 回滚逻辑
数据回滚一般是依靠数据库的Undo日志来保证的。写了一个简单的事务管理器和客户端测试类,可以帮助理解事务的提交、回滚机制。
package transaction;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.Stack;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 线程级事务
* @date 2014-7-4
*/
public class TransactionManager {
// 单例对象
private static final TransactionManager transactionManager = new TransactionManager();
private TransactionManager(){}
// 存储事务相关的变量
public static final ThreadLocal