日期:2014-05-19  浏览次数:20549 次

高手进:关于JTA JOTM XA
用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(