用JOTM写的分布式事务。 能提交,能回滚,但有个重大问题。
在一个业务方法中插入2个表,每表一条记录。多线程并发(10线程 乘以 50次)的访问此业务方法,两个表中的总记录数不一样。
一个少10条,一个少2~3条。
业务方法补贴了,贴上事务实现。
代码1:业务方法代理类,代理所有的业务方法。
package cn.tsb.comm.db.transaction;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.EmptyStackException;
import java.util.Stack;
import javax.transaction.UserTransaction;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.apache.log4j.Logger;
/*
* Copyright (C) 2012 TSB
* All Rights Reserved
* Description: 方法拦截,事务管理
*
* Modification History:
**********************************************************
* Date Author Comments
**********************************************************
* 2012/9/19 Init Version
*/
public abstract class TransactionProxy implements MethodInterceptor {
private static Logger log = Logger.getLogger(TransactionProxy.class);
private String ERROR = TMConstants.ERROR+Thread.currentThread().getId()+" | ";
private String DEBUG = TMConstants.DEBUG+Thread.currentThread().getId()+" | ";
//执行堆,以此实现事务的原子性,为空是进入事务开始,再次为空时事务结束
private static final ThreadLocal<Stack<String>> threadLocal = new ThreadLocal<Stack<String>>();
private String methodname = "";
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
methodname = method.getName();
Object ret = null;
if(method.getName().equals("finalize") || method.getName().equals("count")){
ret = proxy.invokeSuper(obj, args);
}else{
try {
// for each new invoke, push stack
if (isEmpty()) {
//begin();
//本来这里应该ut.begin()的。但为了保证事务的开始在获取连接(第一个)之后,所以这里只打印日志。
//有一种情况会出现:假设一个业务方法需要两个连接,第一个连接打开之后,第二个连接打开之前,会ut.begin,不知道是不是这个原因
preBegin();
}
push(method.getName());
//log.debug(DEBUG+"method="+method.getName()+" os="+(threadLocal.get()==null?"0":threadLocal.get().size())+" ts="+(transactionLocal.get()==null?"0":transactionLocal.get().size())+" cs="+(connLocal.get()==null?"0":connLocal.get().size()));
ret = proxy.invokeSuper(obj, args); // do business
// finish once, pop up
methodname = pop();
// check whether commit the transaction
if (isEmpty()) {
commit();
//提交
}
} catch (Throwable e) {
// if it is in the inner of the invoke chain, throw exception
// directly.
methodname = pop();
if (isEmpty()) {
rollback();
//回滚
}
throw e;
} finally {
// check whether close the session
if (isEmpty()) {
close();
//关闭所有连接
threadLocal.remove();
}