public void executeBatchNodeCmd(SQLCtrlCommand cmdHandler) {
    this.cmdHandler = cmdHandler;
    final int initCount = session.getTargetCount();
    runningCount.set(initCount);
    nodeCount = initCount;
    failed.set(false);
    faileCount.set(0);
    // 执行
    int started = 0;
    for (RouteResultsetNode rrn : session.getTargetKeys()) {
      if (rrn == null) {
        LOGGER.error("null is contained in RoutResultsetNodes, source = " + session.getSource());
        continue;
      }
      final BackendConnection conn = session.getTarget(rrn);
      if (conn != null) {
        conn.setResponseHandler(this);
        cmdHandler.sendCommand(session, conn);
        ++started;
      }
    }

    if (started < nodeCount) {
      runningCount.set(started);
      LOGGER.warn("some connection failed to execut " + (nodeCount - started));
      /**
       * assumption: only caused by front-end connection close. <br>
       * Otherwise, packet must be returned to front-end
       */
      failed.set(true);
    }
  }
  public void rollback() {
    final int initCount = session.getTargetCount();
    lock.lock();
    try {
      reset(initCount);
    } finally {
      lock.unlock();
    }
    if (session.closed()) {
      decrementCountToZero();
      return;
    }

    // 执行
    int started = 0;
    for (final RouteResultsetNode node : session.getTargetKeys()) {
      if (node == null) {
        try {
          LOGGER.error("null is contained in RoutResultsetNodes, source = " + session.getConInfo());
        } catch (Exception e) {
        }
        continue;
      }
      final BackendConnection conn = session.getTarget(node);
      if (conn != null) {
        if (LOGGER.isDebugEnabled()) {
          LOGGER.debug("rollback job run for " + conn);
        }
        if (clearIfSessionClosed(session)) {
          return;
        }
        conn.setResponseHandler(RollbackNodeHandler.this);
        conn.rollback();

        ++started;
      }
    }

    if (started < initCount && decrementCountBy(initCount - started)) {
      /**
       * assumption: only caused by front-end connection close. <br>
       * Otherwise, packet must be returned to front-end
       */
      session.clearResources(true);
    }
  }
  public void releaseConnection(RouteResultsetNode rrn, boolean debug, final boolean needRollback) {

    BackendConnection c = target.remove(rrn);
    if (c != null) {
      if (debug) {
        LOGGER.debug("release connection " + c);
      }
      if (c.getAttachment() != null) {
        c.setAttachment(null);
      }
      if (!c.isClosed()) {
        if (c.isAutocommit()) {
          c.release();
        } else if (needRollback) {
          c.setResponseHandler(new RollbackReleaseHandler());
          c.rollback();
        } else {
          c.release();
        }
      }
    }
  }