All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jfaster.mango.operator.BatchUpdateOperator Maven / Gradle / Ivy

There is a newer version: 2.0.1
Show newest version
/*
 * Copyright 2014 mango.jfaster.org
 *
 * The Mango Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package org.jfaster.mango.operator;

import org.jfaster.mango.binding.BoundSql;
import org.jfaster.mango.binding.InvocationContext;
import org.jfaster.mango.descriptor.MethodDescriptor;
import org.jfaster.mango.exception.DescriptionException;
import org.jfaster.mango.parser.ASTRootNode;
import org.jfaster.mango.stat.OneExecuteStat;
import org.jfaster.mango.transaction.*;
import org.jfaster.mango.util.Iterables;
import org.jfaster.mango.util.ToStringHelper;

import javax.sql.DataSource;
import java.util.*;

/**
 * @author ash
 */
public class BatchUpdateOperator extends AbstractOperator {

  protected Transformer transformer;

  public BatchUpdateOperator(ASTRootNode rootNode, MethodDescriptor md, Config config) {
    super(rootNode, md, config);
    transformer = TRANSFORMERS.get(md.getReturnRawType());
    if (transformer == null) {
      String expected = ToStringHelper.toString(TRANSFORMERS.keySet());
      throw new DescriptionException("the return type of batch update " +
          "expected one of " + expected + " but " + md.getReturnRawType());
    }
  }

  @Override
  public Object execute(Object[] values, OneExecuteStat stat) {
    Iterables iterables = getIterables(values);
    if (iterables.isEmpty()) {
      return transformer.transform(new int[]{});
    }

    Map gorupMap = new HashMap();
    int t = 0;
    for (Object obj : iterables) {
      InvocationContext context = invocationContextFactory.newInvocationContext(new Object[]{obj});
      group(context, gorupMap, t++);
    }
    int[] ints = executeDb(gorupMap, t, stat);
    return transformer.transform(ints);
  }

  protected void group(InvocationContext context, Map groupMap, int position) {
    context.setGlobalTable(tableGenerator.getTable(context));
    DataSource ds = dataSourceGenerator.getDataSource(context, daoClass);
    Group group = groupMap.get(ds);
    if (group == null) {
      group = new Group();
      groupMap.put(ds, group);
    }

    rootNode.render(context);
    BoundSql boundSql = context.getBoundSql();
    invocationInterceptorChain.intercept(boundSql, context); // 拦截器

    group.add(boundSql, position);
  }

  protected Iterables getIterables(Object[] values) {
    Object firstValue = values[0];
    if (firstValue == null) {
      throw new NullPointerException("batchUpdate's parameter can't be null");
    }
    Iterables iterables = new Iterables(firstValue);
    return iterables;
  }

  protected int[] executeDb(Map groupMap, int batchNum, OneExecuteStat stat) {
    int[] r = new int[batchNum];
    long now = System.nanoTime();
    int t = 0;
    try {
      for (Map.Entry entry : groupMap.entrySet()) {
        DataSource ds = entry.getKey();
        List boundSqls = entry.getValue().getBoundSqls();
        List positions = entry.getValue().getPositions();
        int[] ints = config.isUseTransactionForBatchUpdate() ?
            useTransactionBatchUpdate(ds, boundSqls) :
            jdbcOperations.batchUpdate(ds, boundSqls);
        for (int i = 0; i < ints.length; i++) {
          r[positions.get(i)] = ints[i];
        }
        t++;
      }
    } finally {
      long cost = System.nanoTime() - now;
      if (t == groupMap.entrySet().size()) {
        stat.recordDatabaseExecuteSuccess(cost);
      } else {
        stat.recordDatabaseExecuteException(cost);
      }
    }
    return r;
  }

  private int[]  useTransactionBatchUpdate(DataSource ds, List boundSqls) {
    int[] ints;
    Transaction transaction = TransactionFactory.newTransaction(ds);
    try {
      ints = jdbcOperations.batchUpdate(ds, boundSqls);
    } catch (RuntimeException e) {
      transaction.rollback();
      throw e;
    }
    transaction.commit();
    return ints;
  }

  protected static class Group {
    private List boundSqls = new LinkedList();
    private List positions = new LinkedList();

    public void add(BoundSql boundSql, int position) {
      boundSqls.add(boundSql);
      positions.add(position);
    }

    public List getBoundSqls() {
      return boundSqls;
    }

    public List getPositions() {
      return positions;
    }
  }

  private final static Map TRANSFORMERS = new LinkedHashMap();

  static {
    TRANSFORMERS.put(void.class, VoidTransformer.INSTANCE);
    TRANSFORMERS.put(int.class, IntegerTransformer.INSTANCE);
    TRANSFORMERS.put(int[].class, IntArrayTransformer.INSTANCE);
    TRANSFORMERS.put(Void.class, VoidTransformer.INSTANCE);
    TRANSFORMERS.put(Integer.class, IntegerTransformer.INSTANCE);
    TRANSFORMERS.put(Integer[].class, IntegerArrayTransformer.INSTANCE);
  }

  public interface Transformer {
    Object transform(int[] s);
  }

  enum IntArrayTransformer implements Transformer {
    INSTANCE;

    @Override
    public Object transform(int[] s) {
      return s;
    }
  }

  enum IntegerArrayTransformer implements Transformer {
    INSTANCE;

    @Override
    public Object transform(int[] s) {
      Integer[] r = new Integer[s.length];
      for (int i = 0; i < s.length; i++) {
        r[i] = s[i];
      }
      return r;
    }
  }

  enum IntegerTransformer implements Transformer {
    INSTANCE;

    @Override
    public Object transform(int[] s) {
      int r = 0;
      for (int e : s) {
        r += e;
      }
      return r;
    }
  }

  enum VoidTransformer implements Transformer {
    INSTANCE;

    @Override
    public Object transform(int[] s) {
      return null;
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy