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

com.github.javaclub.cdl.client.matrix.jdbc.SMatrixPreparedStatement Maven / Gradle / Ivy

There is a newer version: 2.3.9
Show newest version
package com.github.javaclub.cdl.client.matrix.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.github.javaclub.cdl.client.matrix.executor.PreparedStatementExecutor;
import com.github.javaclub.cdl.client.matrix.jdbc.adapter.AbstractPreparedStatementAdapter;
import com.github.javaclub.cdl.client.matrix.merger.ResultSetFactory;
import com.github.javaclub.cdl.client.matrix.router.SQLExecutionUnit;
import com.github.javaclub.cdl.client.matrix.router.SQLRouteEngine;
import com.github.javaclub.cdl.client.matrix.router.SQLRouteResult;
import com.github.javaclub.cdl.client.parameter.Parameters;
import com.github.javaclub.cdl.client.util.SQLMonitors;
import com.google.common.collect.Lists;


public class SMatrixPreparedStatement extends AbstractPreparedStatementAdapter {
	private static final Logger log = LoggerFactory.getLogger(SMatrixPreparedStatement.class);
    private final String sql;
    
    private final Collection cachedRoutedPreparedStatements = new LinkedList<>();
    
    private Integer autoGeneratedKeys;
    
    private int[] columnIndexes;
    
    private String[] columnNames;
    
    private boolean hasExecuted;
    
    private final List> batchParameters = new ArrayList<>();
    
    public SMatrixPreparedStatement(final SQLRouteEngine sqlRouteEngine, final SMatrixConnection shardingConnection, final String sql, final int autoGeneratedKeys) throws SQLException {
        this(sqlRouteEngine, shardingConnection, sql);
        this.autoGeneratedKeys = autoGeneratedKeys;
    }
    
    public SMatrixPreparedStatement(final SQLRouteEngine sqlRouteEngine, final SMatrixConnection shardingConnection, final String sql, final int[] columnIndexes) throws SQLException {
        this(sqlRouteEngine, shardingConnection, sql);
        this.columnIndexes = columnIndexes;
    }
    
    public SMatrixPreparedStatement(final SQLRouteEngine sqlRouteEngine, final SMatrixConnection shardingConnection, final String sql, final String[] columnNames) throws SQLException {
        this(sqlRouteEngine, shardingConnection, sql);
        this.columnNames = columnNames;
    }
    
    public SMatrixPreparedStatement(final SQLRouteEngine sqlRouteEngine, final SMatrixConnection shardingConnection, final String sql) throws SQLException {
        this(sqlRouteEngine, shardingConnection, sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
    }
    
    public SMatrixPreparedStatement(final SQLRouteEngine sqlRouteEngine, final SMatrixConnection shardingConnection, 
            final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException {
        this(sqlRouteEngine, shardingConnection, sql, resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT);
    }
    
    public SMatrixPreparedStatement(final SQLRouteEngine sqlRouteEngine, final SMatrixConnection shardingConnection, 
            final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException {
        super(sqlRouteEngine, shardingConnection, resultSetType, resultSetConcurrency, resultSetHoldability);
        this.sql = sql;
    }
    
    @Override
    public ResultSet executeQuery() throws SQLException {
    	try{
    		SQLMonitors.entry("matrix-ps-executeQuery");
    		hasExecuted = true;
            setCurrentResultSet(ResultSetFactory.getResultSet(new PreparedStatementExecutor(getRoutedPreparedStatements()).executeQuery(), getMergeContext()));
            return getCurrentResultSet();
    	}finally{
    		SQLMonitors.exit("matrix-ps-executeQuery",true);
    	}
    }
    
    @Override
    public int executeUpdate() throws SQLException {
    	try{
    		SQLMonitors.entry("matrix-ps-executeUpdate");
    		hasExecuted = true;
            return new PreparedStatementExecutor(getRoutedPreparedStatements()).executeUpdate();
    	}finally{
    		SQLMonitors.exit("matrix-ps-executeUpdate",true);
    	}
    }
    
    @Override
    public boolean execute() throws SQLException {
    	try{
    		SQLMonitors.entry("matrix-ps-execute");
    		hasExecuted = true;
            return new PreparedStatementExecutor(getRoutedPreparedStatements()).execute();
    	}finally{
    		SQLMonitors.exit("matrix-ps-execute",true);
    	}
        
    }
    
    @Override
    public void addBatch() throws SQLException {
        batchParameters.add(Lists.newArrayList(getParameters()));
        clearParameters();
    }
    
    @Override
    public void clearBatch() throws SQLException {
        batchParameters.clear();
    }
    
    @Override
    public int[] executeBatch() throws SQLException {
        hasExecuted = true;
        int[] result = new int[batchParameters.size()];
        int i = 0;
        for (List each : batchParameters) {
        	List routePreparedStatements = routeSQL(each);
            cachedRoutedPreparedStatements.addAll(routePreparedStatements);
            result[i++] = new PreparedStatementExecutor(routePreparedStatements).executeUpdate();
        }
        return result;
    }
    
    private Collection getRoutedPreparedStatements() throws SQLException {
        if (!hasExecuted) {
            return Collections.emptyList();
        }
        routeIfNeed();
        return cachedRoutedPreparedStatements;
    }
    
    @Override
    public Collection getRoutedStatements() throws SQLException {
        return getRoutedPreparedStatements();
    }
    
    private void routeIfNeed() throws SQLException {
        if (!cachedRoutedPreparedStatements.isEmpty()) {
            return;
        }
        cachedRoutedPreparedStatements.addAll(routeSQL(getParameters()));
    }
    
    private List routeSQL(final List parameters) throws SQLException {
        List result = new ArrayList<>();
        SQLRouteResult sqlRouteResult = getSqlRouteEngine().route(sql, parameters,parameterSettings);
        if(sqlRouteResult.isNotShardTable()){
        	setNotShard(true);
        }
        setMergeContext(sqlRouteResult.getMergeContext());
		log.debug("route size:{}  {}  {}", sqlRouteResult.getExecutionUnits().size(), sql,parameters);
        for (SQLExecutionUnit each : sqlRouteResult.getExecutionUnits()) {
        	log.debug("one route:{},{}", each.getGroupName(), each.getSql());
            PreparedStatement preparedStatement = generatePrepareStatement(getShardingConnection().getConnection(each.getGroupName()), each.getSql());
            replayMethodsInvovation(preparedStatement);
            setParameters(preparedStatement);
            result.add(preparedStatement);
        }
        return result;
    }
    
    private PreparedStatement generatePrepareStatement(final Connection conn, final String shardingSql) throws SQLException {
        if (null != autoGeneratedKeys) {
            return conn.prepareStatement(shardingSql, autoGeneratedKeys);
        }
        if (null != columnIndexes) {
            return conn.prepareStatement(shardingSql, columnIndexes);
        }
        if (null != columnNames) {
            return conn.prepareStatement(shardingSql, columnNames);
        }
        if (0 != getResultSetHoldability()) {
            return conn.prepareStatement(shardingSql, getResultSetType(), getResultSetConcurrency(), getResultSetHoldability());
        }
        return conn.prepareStatement(shardingSql, getResultSetType(), getResultSetConcurrency());
    }
    
    private void setParameters(final PreparedStatement preparedStatement) throws SQLException {
    	Parameters.setParameters(preparedStatement, parameterSettings);
    }
}