com.taobao.tddl.jdbc.group.TGroupStatement.java Source code

Java tutorial

Introduction

Here is the source code for com.taobao.tddl.jdbc.group.TGroupStatement.java

Source

/*(C) 2007-2012 Alibaba Group Holding Limited.   
 *This program is free software; you can redistribute it and/or modify   
*it under the terms of the GNU General Public License version 2 as   
* published by the Free Software Foundation.   
* Authors:   
*   junyu <junyu@taobao.com> , shenxun <shenxun@taobao.com>,   
*   linxuan <linxuan@taobao.com> ,qihao <qihao@taobao.com>    
*/
package com.taobao.tddl.jdbc.group;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.taobao.tddl.interact.rule.bean.SqlType;
import com.taobao.tddl.jdbc.group.dbselector.DBSelector.AbstractDataSourceTryer;
import com.taobao.tddl.jdbc.group.dbselector.DBSelector.DataSourceTryer;
import com.taobao.tddl.jdbc.group.util.GroupHintParser;
import com.taobao.tddl.jdbc.group.util.SQLParser;

/**
 *
 * @author linxuan
 * @author yangzhu
 *
 */
public class TGroupStatement implements Statement {
    private static final Log log = LogFactory.getLog(TGroupStatement.class);

    protected TGroupConnection tGroupConnection;
    protected TGroupDataSource tGroupDataSource;
    protected int retryingTimes;

    public TGroupStatement(TGroupDataSource tGroupDataSource, TGroupConnection tGroupConnection) {
        this.tGroupDataSource = tGroupDataSource;
        this.tGroupConnection = tGroupConnection;

        this.retryingTimes = tGroupDataSource.getRetryingTimes();
    }

    /* ========================================================================
     * ()Statementgetter/setter
     * ======================================================================*/
    private Statement baseStatement;

    /**
     * Statement
     * baseStatement
     * @param baseStatement
     */
    void setBaseStatement(Statement baseStatement) {
        if (this.baseStatement != null) {
            try {
                this.baseStatement.close();
            } catch (SQLException e) {
                log.error("close baseStatement failed.", e);
            }
        }
        this.baseStatement = baseStatement;
    }

    /**
     * query time out . 0setquery
     */
    protected int queryTimeout = 0;

    protected int fetchSize;

    protected int maxRows;

    /**
     *  getResult.
     *
     * statement
     */
    protected ResultSet currentResultSet;
    /**
     *  query-1
     */
    protected int updateCount;

    protected int resultSetType = ResultSet.TYPE_FORWARD_ONLY;;
    protected int resultSetConcurrency = ResultSet.CONCUR_READ_ONLY;

    //jdbcresultSetHoldabilityResultSet.CLOSE_CURSORS_AT_COMMIT?
    //TODO -1?
    protected int resultSetHoldability = -1;

    public boolean execute(String sql) throws SQLException {
        return executeInternal(sql, -1, null, null);
    }

    public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
        return executeInternal(sql, autoGeneratedKeys, null, null);
    }

    public boolean execute(String sql, int[] columnIndexes) throws SQLException {
        return executeInternal(sql, -1, columnIndexes, null);
    }

    public boolean execute(String sql, String[] columnNames) throws SQLException {
        return executeInternal(sql, -1, null, columnNames);
    }

    //jdbc: trueexecuteQueryfalseexecuteUpdate
    private boolean executeInternal(String sql, int autoGeneratedKeys, int[] columnIndexes, String[] columnNames)
            throws SQLException {

        SqlType sqlType = SQLParser.getSqlType(sql);
        if (sqlType == SqlType.SELECT || sqlType == SqlType.SELECT_FOR_UPDATE || sqlType == SqlType.SHOW) {
            executeQuery(sql);
            return true;
        } else if (sqlType == SqlType.INSERT || sqlType == SqlType.UPDATE || sqlType == SqlType.DELETE
                || sqlType == SqlType.REPLACE || sqlType == SqlType.TRUNCATE || sqlType == SqlType.CREATE
                || sqlType == SqlType.DROP || sqlType == SqlType.LOAD || sqlType == SqlType.MERGE) {
            if (autoGeneratedKeys == -1 && columnIndexes == null && columnNames == null) {
                executeUpdate(sql);
            } else if (autoGeneratedKeys != -1) {
                executeUpdate(sql, autoGeneratedKeys);
            } else if (columnIndexes != null) {
                executeUpdate(sql, columnIndexes);
            } else if (columnNames != null) {
                executeUpdate(sql, columnNames);
            } else {
                executeUpdate(sql);
            }

            return false;
        } else {
            throw new SQLException(
                    "only select, insert, update, delete,replace,truncate,create,drop,load,merge sql is supported");
        }
    }

    /* ========================================================================
     * executeUpdate
     * ======================================================================*/
    public int executeUpdate(String sql) throws SQLException {
        return executeUpdateInternal(sql, -1, null, null);
    }

    public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
        return executeUpdateInternal(sql, autoGeneratedKeys, null, null);
    }

    public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
        return executeUpdateInternal(sql, -1, columnIndexes, null);
    }

    public int executeUpdate(String sql, String[] columnNames) throws SQLException {
        return executeUpdateInternal(sql, -1, null, columnNames);
    }

    private int executeUpdateInternal(String sql, int autoGeneratedKeys, int[] columnIndexes, String[] columnNames)
            throws SQLException {
        checkClosed();
        ensureResultSetIsEmpty();

        Connection conn = tGroupConnection.getBaseConnection(sql, false);

        if (conn != null) {
            sql = GroupHintParser.removeTddlGroupHint(sql);
            this.updateCount = executeUpdateOnConnection(conn, sql, autoGeneratedKeys, columnIndexes, columnNames);
            return this.updateCount;
        } else {
            Integer dataSourceIndex = GroupHintParser.convertHint2Index(sql);
            sql = GroupHintParser.removeTddlGroupHint(sql);
            if (dataSourceIndex < 0) {
                dataSourceIndex = ThreadLocalDataSourceIndex.getIndex();
            }
            this.updateCount = this.tGroupDataSource.getDBSelector(false).tryExecute(executeUpdateTryer,
                    retryingTimes, sql, autoGeneratedKeys, columnIndexes, columnNames, dataSourceIndex);
            return this.updateCount;
        }
    }

    private int executeUpdateOnConnection(Connection conn, String sql, int autoGeneratedKeys, int[] columnIndexes,
            String[] columnNames) throws SQLException {
        Statement stmt = createStatementInternal(conn, false);

        if (autoGeneratedKeys == -1 && columnIndexes == null && columnNames == null) {
            return stmt.executeUpdate(sql);
        } else if (autoGeneratedKeys != -1) {
            return stmt.executeUpdate(sql, autoGeneratedKeys);
        } else if (columnIndexes != null) {
            return stmt.executeUpdate(sql, columnIndexes);
        } else if (columnNames != null) {
            return stmt.executeUpdate(sql, columnNames);
        } else {
            return stmt.executeUpdate(sql);
        }
    }

    private DataSourceTryer<Integer> executeUpdateTryer = new AbstractDataSourceTryer<Integer>() {
        public Integer tryOnDataSource(DataSourceWrapper dsw, Object... args) throws SQLException {
            Connection conn = TGroupStatement.this.tGroupConnection.createNewConnection(dsw, false);
            return executeUpdateOnConnection(conn, (String) args[0], (Integer) args[1], (int[]) args[2],
                    (String[]) args[3]);
        }
    };

    /**
     * setBaseStatementStatement
     */
    private Statement createStatementInternal(Connection conn, boolean isBatch) throws SQLException {
        Statement stmt;
        if (isBatch)
            stmt = conn.createStatement();
        else {
            int resultSetHoldability = this.resultSetHoldability;
            if (resultSetHoldability == -1) //setResultSetHoldability
                resultSetHoldability = conn.getHoldability();

            stmt = conn.createStatement(this.resultSetType, this.resultSetConcurrency, resultSetHoldability);
        }

        setBaseStatement(stmt); //Statement
        stmt.setQueryTimeout(queryTimeout); //
        stmt.setFetchSize(fetchSize);
        stmt.setMaxRows(maxRows);

        return stmt;
    }

    /* ========================================================================
     * executeBatch
     * ======================================================================*/
    protected List<String> batchedArgs;

    public void addBatch(String sql) throws SQLException {
        checkClosed();
        if (batchedArgs == null) {
            batchedArgs = new LinkedList<String>();
        }
        if (sql != null) {
            batchedArgs.add(sql);
        }
    }

    public void clearBatch() throws SQLException {
        checkClosed();
        if (batchedArgs != null) {
            batchedArgs.clear();
        }
    }

    public int[] executeBatch() throws SQLException {
        try {
            checkClosed();
            ensureResultSetIsEmpty();

            if (batchedArgs == null || batchedArgs.isEmpty()) {
                return new int[0];
            }

            Connection conn = tGroupConnection.getBaseConnection(null, false);

            if (conn != null) {
                // ,
                // getConnection
                return executeBatchOnConnection(conn, this.batchedArgs);
            } else {
                return tGroupDataSource.getDBSelector(false).tryExecute(null, executeBatchTryer, retryingTimes);
            }
        } finally {
            if (batchedArgs != null)
                batchedArgs.clear();
        }
    }

    private DataSourceTryer<int[]> executeBatchTryer = new AbstractDataSourceTryer<int[]>() {
        public int[] tryOnDataSource(DataSourceWrapper dsw, Object... args) throws SQLException {
            Connection conn = TGroupStatement.this.tGroupConnection.createNewConnection(dsw, false);
            return executeBatchOnConnection(conn, TGroupStatement.this.batchedArgs);
        }
    };

    private int[] executeBatchOnConnection(Connection conn, List<String> batchedSqls) throws SQLException {
        Statement stmt = createStatementInternal(conn, true);
        for (String sql : batchedSqls) {
            stmt.addBatch(sql);
        }
        return stmt.executeBatch();
    }

    /* ========================================================================
     * 
     * ======================================================================*/
    protected boolean closed; //statment 

    public void close() throws SQLException {
        close(true);
    }

    void close(boolean removeThis) throws SQLException {
        if (closed) {
            return;
        }
        closed = true;

        try {
            if (currentResultSet != null)
                currentResultSet.close();
        } catch (SQLException e) {
            log.warn("Close currentResultSet failed.", e);
        } finally {
            currentResultSet = null;
        }

        try {
            if (this.baseStatement != null)
                this.baseStatement.close();
        } finally {
            this.baseStatement = null;
            if (removeThis)
                tGroupConnection.removeOpenedStatements(this);
        }
    }

    protected void checkClosed() throws SQLException {
        if (closed) {
            throw new SQLException("No operations allowed after statement closed.");
        }
    }

    /**
     * jdbc
     *
     * @throws SQLException
     */
    protected void ensureResultSetIsEmpty() throws SQLException {

        if (currentResultSet != null) {
            //log.debug("result set is not null,close current result set");
            try {
                currentResultSet.close();
            } catch (SQLException e) {
                log.error("exception on close last result set . can do nothing..", e);
            } finally {
                // 
                currentResultSet = null;
            }
        }

    }

    /* ========================================================================
     * executeQuery 
     * ======================================================================*/
    public ResultSet executeQuery(String sql) throws SQLException {
        checkClosed();
        ensureResultSetIsEmpty();

        boolean gotoRead = SqlType.SELECT.equals(SQLParser.getSqlType(sql)) && tGroupConnection.getAutoCommit();
        Connection conn = tGroupConnection.getBaseConnection(sql, gotoRead);

        if (conn != null) {
            sql = GroupHintParser.removeTddlGroupHint(sql);
            return executeQueryOnConnection(conn, sql);
        } else {
            // hint
            Integer dataSourceIndex = GroupHintParser.convertHint2Index(sql);
            sql = GroupHintParser.removeTddlGroupHint(sql);
            if (dataSourceIndex < 0) {
                dataSourceIndex = ThreadLocalDataSourceIndex.getIndex();
            }
            return this.tGroupDataSource.getDBSelector(gotoRead).tryExecute(executeQueryTryer, retryingTimes, sql,
                    dataSourceIndex);
        }
    }

    protected ResultSet executeQueryOnConnection(Connection conn, String sql) throws SQLException {
        Statement stmt = createStatementInternal(conn, false);
        this.currentResultSet = stmt.executeQuery(sql);
        return this.currentResultSet;
    }

    protected DataSourceTryer<ResultSet> executeQueryTryer = new AbstractDataSourceTryer<ResultSet>() {
        public ResultSet tryOnDataSource(DataSourceWrapper dsw, Object... args) throws SQLException {
            String sql = (String) args[0];
            Connection conn = TGroupStatement.this.tGroupConnection.createNewConnection(dsw, true);
            return executeQueryOnConnection(conn, sql);
        }
    };

    public SQLWarning getWarnings() throws SQLException {
        checkClosed();
        if (baseStatement != null)
            return baseStatement.getWarnings();
        return null;
    }

    public void clearWarnings() throws SQLException {
        checkClosed();
        if (baseStatement != null)
            baseStatement.clearWarnings();
    }

    /* ========================================================================
     * 
     * ======================================================================*/
    /**
     *  
     */
    protected boolean moreResults;

    public boolean getMoreResults() throws SQLException {
        return moreResults;
    }

    public int getQueryTimeout() throws SQLException {
        return queryTimeout;
    }

    public void setQueryTimeout(int queryTimeout) throws SQLException {
        this.queryTimeout = queryTimeout;
    }

    public ResultSet getResultSet() throws SQLException {
        return currentResultSet;
    }

    public int getUpdateCount() throws SQLException {
        return updateCount;
    }

    public int getResultSetConcurrency() throws SQLException {
        return resultSetConcurrency;
    }

    public int getResultSetHoldability() throws SQLException {
        return resultSetHoldability;
    }

    public int getResultSetType() throws SQLException {
        return resultSetType;
    }

    public void setResultSetType(int resultSetType) {
        this.resultSetType = resultSetType;
    }

    public void setResultSetConcurrency(int resultSetConcurrency) {
        this.resultSetConcurrency = resultSetConcurrency;
    }

    public void setResultSetHoldability(int resultSetHoldability) {
        this.resultSetHoldability = resultSetHoldability;
    }

    public Connection getConnection() throws SQLException {
        return tGroupConnection;
    }

    /* ========================================================================
     * 
     * ======================================================================*/
    public int getFetchDirection() throws SQLException {
        throw new UnsupportedOperationException("getFetchDirection");
    }

    public int getFetchSize() throws SQLException {
        return this.fetchSize;
    }

    public int getMaxFieldSize() throws SQLException {
        throw new UnsupportedOperationException("getMaxFieldSize");
    }

    public int getMaxRows() throws SQLException {
        return this.maxRows;
    }

    public void setCursorName(String cursorName) throws SQLException {
        throw new UnsupportedOperationException("setCursorName");
    }

    public void setEscapeProcessing(boolean escapeProcessing) throws SQLException {
        throw new UnsupportedOperationException("setEscapeProcessing");
    }

    public boolean getMoreResults(int current) throws SQLException {
        throw new UnsupportedOperationException("getMoreResults");
    }

    public void setFetchDirection(int fetchDirection) throws SQLException {
        throw new UnsupportedOperationException("setFetchDirection");
    }

    public void setFetchSize(int fetchSize) throws SQLException {
        this.fetchSize = fetchSize;
    }

    public void setMaxFieldSize(int maxFieldSize) throws SQLException {
        throw new UnsupportedOperationException("setMaxFieldSize");
    }

    public void setMaxRows(int maxRows) throws SQLException {
        this.maxRows = maxRows;
    }

    public ResultSet getGeneratedKeys() throws SQLException {
        if (this.baseStatement != null)
            return this.baseStatement.getGeneratedKeys();
        else
            throw new SQLException("getGeneratedKeys");
        //throw new UnsupportedOperationException("getGeneratedKeys");
    }

    public void cancel() throws SQLException {
        throw new UnsupportedOperationException("cancel");
    }

    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return this.getClass().isAssignableFrom(iface);
    }

    @SuppressWarnings("unchecked")
    public <T> T unwrap(Class<T> iface) throws SQLException {
        try {
            return (T) this;
        } catch (Exception e) {
            throw new SQLException(e);
        }
    }

    public boolean isClosed() throws SQLException {
        throw new SQLException("not support exception");
    }

    public void setPoolable(boolean poolable) throws SQLException {
        throw new SQLException("not support exception");
    }

    public boolean isPoolable() throws SQLException {
        throw new SQLException("not support exception");
    }
}