Package cn.dreampie.common.plugin.db.tx

Source Code of cn.dreampie.common.plugin.db.tx.XATx

package cn.dreampie.common.plugin.db.tx;

/**
* Created by wangrenhui on 2014/5/9.
*/

import com.jfinal.aop.Interceptor;
import com.jfinal.core.ActionInvocation;
import com.jfinal.plugin.activerecord.ActiveRecordException;
import com.jfinal.plugin.activerecord.Config;
import com.jfinal.plugin.activerecord.DbKit;

import javax.sql.XAConnection;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import java.sql.Connection;
import java.sql.SQLException;

/**
* ActiveRecord declare transaction.
* Example: @Before(Tx.class)
*/
public class XATx implements Interceptor {

  static Config[] getConfigWithAXTxConfigs(ActionInvocation ai) {
    AXTxConfig axTxConfig = ai.getMethod().getAnnotation(AXTxConfig.class);
    if (axTxConfig == null)
      axTxConfig = ai.getController().getClass().getAnnotation(AXTxConfig.class);

    if (axTxConfig != null) {
      Config[] configs = null;
      String[] names = axTxConfig.value();
      if (names != null && names.length > 0) {
        int length = names.length;
        configs = new Config[length];
        int i = 0;
        for (String conf : names) {
          configs[i] = DbKit.getConfig(conf);
          i++;
        }
      }
      if (configs == null)
        throw new RuntimeException("Config not found with AXTxConfig");
      return configs;
    }
    return null;
  }

  protected int getTransactionLevel(Config config) {
    return config.getTransactionLevel();
  }

  static int tid = 0;

  public void intercept(ActionInvocation ai) {
    Config[] configs = getConfigWithAXTxConfigs(ai);
    XAXid xid = XAXid.uniqueXid(++tid);
    if (configs != null && configs.length > 0) {
      boolean r = true;
      XAResult[] xaResults = new XAResult[configs.length];
      int i = 0;
      for (Config c : configs) {
        //当前配置的数据源的预执行结果
        xaResults[i] = prepare(ai, c, xid);
        r = r && (xaResults[i].getXaResource() != null);
        i++;
      }
      //如果执行没有错误
      if (r) {
        Connection connection = null;
        for (XAResult xaResult : xaResults) {
          connection = ((Connection) xaResult.getXaConnection());
          try {
            xaResult.getXaResource().commit(xid, false);
          } catch (XAException xae) {
            throw new ActiveRecordException(xae);
          } finally {
            try {
              if (connection != null) {
                if (xaResult.getAutoCommit() != null) {
                  connection.setAutoCommit(xaResult.getAutoCommit());
                }
              }
            } catch (Exception e) {
              e.printStackTrace();    // can not throw exception here, otherwise the more important exception in previous catch block can not be thrown
            } finally {
              if (xaResult.isRemoveConnection())
                xaResult.getConfig().removeThreadLocalConnection();    // prevent memory leak
            }
          }
        }
      }
    }
    tid--;
  }

  private XAResult prepare(ActionInvocation ai, Config config, Xid xid) {
    XAConnection xaConn = null;
    Connection conn = config.getThreadLocalConnection();
    if (conn != null) {    // Nested transaction support

      xaConn = (XAConnection) conn;
      try {
        if (conn.getTransactionIsolation() < getTransactionLevel(config))
          conn.setTransactionIsolation(getTransactionLevel(config));
        //返回resource
        return new XAResult(config, prepareInvoke(xaConn, xid, ai), xaConn, null, false);
      } catch (SQLException e) {
        throw new ActiveRecordException(e);
      } catch (XAException xae) {
        throw new ActiveRecordException(xae);
      }
    }

    Boolean autoCommit = null;
    try {
      conn = config.getConnection();
      autoCommit = conn.getAutoCommit();
      config.setThreadLocalConnection(conn);
      conn.setTransactionIsolation(getTransactionLevel(config));    // conn.setTransactionIsolation(transactionLevel);
      conn.setAutoCommit(false);
      xaConn = (XAConnection) conn;
      return new XAResult(config, prepareInvoke(xaConn, xid, ai), xaConn, autoCommit, true);
    } catch (Exception e) {
      throw new ActiveRecordException(e);
    }
  }

  private XAResource prepareInvoke(XAConnection xaconn, Xid xid, ActionInvocation ai) throws SQLException, XAException {
    XAResource xaRes = xaconn.getXAResource();
    xaRes.start(xid, XAResource.TMNOFLAGS);
    //操作
    ai.invoke();
    xaRes.end(xid, XAResource.TMSUCCESS);
    int result = xaRes.prepare(xid);
    if (result == XAResource.XA_OK) {
      return xaRes;
    }
    return null;
  }
}
TOP

Related Classes of cn.dreampie.common.plugin.db.tx.XATx

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.