Package net.hasor.db.jdbc.core

Source Code of net.hasor.db.jdbc.core.JdbcTemplate$RowCallbackHandlerResultSetExtractor

/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed 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 net.hasor.db.jdbc.core;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.nio.charset.Charset;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import net.hasor.core.Hasor;
import net.hasor.db.datasource.ConnectionProxy;
import net.hasor.db.datasource.DataSourceUtils;
import net.hasor.db.jdbc.BatchPreparedStatementSetter;
import net.hasor.db.jdbc.CallableStatementCallback;
import net.hasor.db.jdbc.CallableStatementCreator;
import net.hasor.db.jdbc.ConnectionCallback;
import net.hasor.db.jdbc.JdbcOperations;
import net.hasor.db.jdbc.PreparedStatementCallback;
import net.hasor.db.jdbc.PreparedStatementCreator;
import net.hasor.db.jdbc.PreparedStatementSetter;
import net.hasor.db.jdbc.ResultSetExtractor;
import net.hasor.db.jdbc.RowCallbackHandler;
import net.hasor.db.jdbc.RowMapper;
import net.hasor.db.jdbc.SqlParameterSource;
import net.hasor.db.jdbc.StatementCallback;
import net.hasor.db.jdbc.core.mapper.BeanPropertyRowMapper;
import net.hasor.db.jdbc.core.mapper.ColumnMapRowMapper;
import net.hasor.db.jdbc.core.mapper.SingleColumnRowMapper;
import org.more.util.ArrayUtils;
import org.more.util.IOUtils;
import org.more.util.ResourcesUtils;
/**
* 数据库操作模板方法。
* @version : 2013-10-12
* @author 赵永春 (zyc@byshell.org)
*/
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
    /*是否忽略出现的 SQL 警告*/
    private boolean ignoreWarnings         = true;
    /*JDBC查询和从结果集里面每次取设置行数,循环去取,直到取完。合理设置该参数可以避免内存异常。
     * 如果这个变量被设置为非零值,它将被用于设置 statements 的 fetchSize 属性。*/
    private int     fetchSize              = 0;
    /*从 JDBC 中可以查询的最大行数。
     * 如果这个变量被设置为非零值,它将被用于设置 statements 的 maxRows 属性。*/
    private int     maxRows                = 0;
    /*从 JDBC 中可以查询的最大行数。
     * 如果这个变量被设置为非零值,它将被用于设置 statements 的 queryTimeout 属性。*/
    private int     queryTimeout           = 0;
    /*当JDBC 结果集中如出现相同的列名仅仅大小写不同时。是否保留大小写列名敏感。
     * 如果为 true 表示敏感,并且结果集Map中保留两个记录。如果为 false 则表示不敏感,如出现冲突列名后者将会覆盖前者。*/
    private boolean resultsCaseInsensitive = false;
    //
    //
    //
    /**
     * Construct a new JdbcTemplate for bean usage.
     * <p>Note: The DataSource has to be set before using the instance.
     * @see #setDataSource
     */
    public JdbcTemplate() {}
    /**
     * Construct a new JdbcTemplate, given a DataSource to obtain connections from.
     * <p>Note: This will not trigger initialization of the exception translator.
     * @param dataSource the JDBC DataSource to obtain connections from
     */
    public JdbcTemplate(final DataSource dataSource) {
        this.setDataSource(dataSource);
    }
    public JdbcTemplate(final Connection conn) {
        this.setConnection(conn);
    }
    //
    //
    //
    public boolean isIgnoreWarnings() {
        return this.ignoreWarnings;
    }
    public void setIgnoreWarnings(final boolean ignoreWarnings) {
        this.ignoreWarnings = ignoreWarnings;
    }
    public int getFetchSize() {
        return this.fetchSize;
    }
    public void setFetchSize(final int fetchSize) {
        this.fetchSize = fetchSize;
    }
    public int getMaxRows() {
        return this.maxRows;
    }
    public void setMaxRows(final int maxRows) {
        this.maxRows = maxRows;
    }
    public int getQueryTimeout() {
        return this.queryTimeout;
    }
    public void setQueryTimeout(final int queryTimeout) {
        this.queryTimeout = queryTimeout;
    }
    public boolean isResultsCaseInsensitive() {
        return this.resultsCaseInsensitive;
    }
    public void setResultsCaseInsensitive(final boolean resultsCaseInsensitive) {
        this.resultsCaseInsensitive = resultsCaseInsensitive;
    }
    //
    //
    //
    public void loadSQL(final String sqlResource) throws IOException, SQLException {
        this.loadSQL("UTF-8", sqlResource);
    }
    public void loadSQL(final String charsetName, final String sqlResource) throws IOException, SQLException {
        InputStream inStream = ResourcesUtils.getResourceAsStream(sqlResource);
        if (inStream == null) {
            throw new IOException("can't find :" + sqlResource);
        }
        InputStreamReader reader = new InputStreamReader(inStream, Charset.forName(charsetName));
        this.loadSQL(reader);
    }
    public void loadSQL(final Reader sqlReader) throws IOException, SQLException {
        StringWriter outWriter = new StringWriter();
        IOUtils.copy(sqlReader, outWriter);
        this.execute(outWriter.toString());
    }
    /** 判断表是否已经存在*/
    public boolean tableExist(final String name) throws SQLException {
        return this.execute(new ConnectionCallback<Boolean>() {
            @Override
            public Boolean doInConnection(final Connection con) throws SQLException {
                DatabaseMetaData metaData = con.getMetaData();
                ResultSet rs = metaData.getTables(null, null, name.toUpperCase(), new String[] { "TABLE" });
                return rs.next();
            }
        });
    }
    //
    //
    //
    @Override
    public <T> T execute(final ConnectionCallback<T> action) throws SQLException {
        Hasor.assertIsNotNull(action, "Callback object must not be null");
        //
        Connection con = this.getConnection();
        boolean useLocal = false;
        if (con == null) {
            DataSource ds = this.getDataSource();//获取数据源
            con = DataSourceUtils.getConnection(ds);//申请本地连接(和当前线程绑定的连接)
            useLocal = true;
            con = this.newProxyConnection(con, ds);//代理连接
        } else {
            con = this.newProxyConnection(con, null);//代理连接
        }
        //
        try {
            return action.doInConnection(con);
        } catch (SQLException ex) {
            throw ex;
        } finally {
            if (useLocal) {
                DataSourceUtils.releaseConnection(con, this.getDataSource());//关闭或释放连接
            }
        }
    }
    @Override
    public <T> T execute(final StatementCallback<T> action) throws SQLException {
        Hasor.assertIsNotNull(action, "Callback object must not be null");
        return this.execute(new ConnectionCallback<T>() {
            @Override
            public T doInConnection(final Connection con) throws SQLException {
                Statement stmt = null;
                try {
                    stmt = con.createStatement();
                    JdbcTemplate.this.applyStatementSettings(stmt);
                    T result = action.doInStatement(stmt);
                    JdbcTemplate.this.handleWarnings(stmt);
                    return result;
                } catch (SQLException ex) {
                    throw ex;
                } finally {
                    stmt.close();
                }
            }
        });
    }
    @Override
    public <T> T execute(final PreparedStatementCreator psc, final PreparedStatementCallback<T> action) throws SQLException {
        Hasor.assertIsNotNull(psc, "PreparedStatementCreator must not be null");
        Hasor.assertIsNotNull(action, "Callback object must not be null");
        if (Hasor.isDebugLogger()) {
            String sql = JdbcTemplate.getSql(psc);
            Hasor.logDebug("Executing prepared SQL statement " + (sql != null ? " [" + sql + "]" : ""));
        }
        //
        return this.execute(new ConnectionCallback<T>() {
            @Override
            public T doInConnection(final Connection con) throws SQLException {
                PreparedStatement ps = null;
                try {
                    ps = psc.createPreparedStatement(con);
                    JdbcTemplate.this.applyStatementSettings(ps);
                    T result = action.doInPreparedStatement(ps);
                    JdbcTemplate.this.handleWarnings(ps);
                    return result;
                } catch (SQLException ex) {
                    throw ex;
                } finally {
                    if (psc instanceof ParameterDisposer) {
                        ((ParameterDisposer) psc).cleanupParameters();
                    }
                    ps.close();
                }
            }
        });
    }
    @Override
    public <T> T execute(final CallableStatementCreator csc, final CallableStatementCallback<T> action) throws SQLException {
        Hasor.assertIsNotNull(csc, "CallableStatementCreator must not be null");
        Hasor.assertIsNotNull(action, "Callback object must not be null");
        if (Hasor.isDebugLogger()) {
            String sql = JdbcTemplate.getSql(csc);
            Hasor.logDebug("Calling stored procedure" + (sql != null ? " [" + sql + "]" : ""));
        }
        //
        return this.execute(new ConnectionCallback<T>() {
            @Override
            public T doInConnection(final Connection con) throws SQLException {
                CallableStatement cs = null;
                try {
                    cs = csc.createCallableStatement(con);
                    JdbcTemplate.this.applyStatementSettings(cs);
                    T result = action.doInCallableStatement(cs);
                    JdbcTemplate.this.handleWarnings(cs);
                    return result;
                } catch (SQLException ex) {
                    throw new SQLException("CallableStatementCallback SQL :" + JdbcTemplate.getSql(action), ex);
                } finally {
                    if (csc instanceof ParameterDisposer) {
                        ((ParameterDisposer) csc).cleanupParameters();
                    }
                    cs.close();
                }
            }
        });
    }
    @Override
    public <T> T execute(final String sql, final PreparedStatementCallback<T> action) throws SQLException {
        return this.execute(new SimplePreparedStatementCreator(sql), action);
    }
    @Override
    public <T> T execute(final String callString, final CallableStatementCallback<T> action) throws SQLException {
        return this.execute(new SimpleCallableStatementCreator(callString), action);
    }
    @Override
    public <T> T execute(final String sql, final SqlParameterSource paramSource, final PreparedStatementCallback<T> action) throws SQLException {
        return this.execute(this.getPreparedStatementCreator(sql, paramSource), action);
    }
    @Override
    public <T> T execute(final String sql, final Map<String, ?> paramMap, final PreparedStatementCallback<T> action) throws SQLException {
        return this.execute(this.getPreparedStatementCreator(sql, new InnerMapSqlParameterSource(paramMap)), action);
    }
    //
    //
    //
    @Override
    public boolean execute(final String sql) throws SQLException {
        Hasor.logDebug("Executing SQL statement [%s].", sql);
        class ExecuteStatementCallback implements StatementCallback<Boolean>, SqlProvider {
            @Override
            public Boolean doInStatement(final Statement stmt) throws SQLException {
                return stmt.execute(sql);
            }
            @Override
            public String getSql() {
                return sql;
            }
        }
        return this.execute(new ExecuteStatementCallback());
    }
    //
    //
    //
    /***/
    public <T> T query(final PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor<T> rse) throws SQLException {
        Hasor.assertIsNotNull(rse, "ResultSetExtractor must not be null.");
        Hasor.logDebug("Executing prepared SQL query");
        return this.execute(psc, new PreparedStatementCallback<T>() {
            @Override
            public T doInPreparedStatement(final PreparedStatement ps) throws SQLException {
                ResultSet rs = null;
                try {
                    if (pss != null) {
                        pss.setValues(ps);
                    }
                    rs = ps.executeQuery();
                    return rse.extractData(rs);
                } finally {
                    rs.close();
                    if (pss instanceof ParameterDisposer) {
                        ((ParameterDisposer) pss).cleanupParameters();
                    }
                }
            }
        });
    }
    @Override
    public <T> T query(final PreparedStatementCreator psc, final ResultSetExtractor<T> rse) throws SQLException {
        return this.query(psc, null, rse);
    }
    @Override
    public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws SQLException {
        Hasor.assertIsNotNull(sql, "SQL must not be null.");
        Hasor.assertIsNotNull(rse, "ResultSetExtractor must not be null.");
        Hasor.logDebug("Executing SQL query [%s].", sql);
        class QueryStatementCallback implements StatementCallback<T>, SqlProvider {
            @Override
            public T doInStatement(final Statement stmt) throws SQLException {
                ResultSet rs = null;
                try {
                    rs = stmt.executeQuery(sql);
                    return rse.extractData(rs);
                } finally {
                    if (rs != null) {
                        rs.close();
                    }
                    rs = null;
                }
            }
            @Override
            public String getSql() {
                return sql;
            }
        }
        return this.execute(new QueryStatementCallback());
    }
    @Override
    public <T> T query(final String sql, final PreparedStatementSetter pss, final ResultSetExtractor<T> rse) throws SQLException {
        return this.query(new SimplePreparedStatementCreator(sql), pss, rse);
    }
    @Override
    public <T> T query(final String sql, final ResultSetExtractor<T> rse, final Object... args) throws SQLException {
        return this.query(sql, this.newArgPreparedStatementSetter(args), rse);
    }
    @Override
    public <T> T query(final String sql, final Object[] args, final ResultSetExtractor<T> rse) throws SQLException {
        return this.query(sql, this.newArgPreparedStatementSetter(args), rse);
    }
    @Override
    public <T> T query(final String sql, final SqlParameterSource paramSource, final ResultSetExtractor<T> rse) throws SQLException {
        return this.query(this.getPreparedStatementCreator(sql, paramSource), rse);
    }
    @Override
    public <T> T query(final String sql, final Map<String, ?> paramMap, final ResultSetExtractor<T> rse) throws SQLException {
        return this.query(this.getPreparedStatementCreator(sql, new InnerMapSqlParameterSource(paramMap)), rse);
    }
    //
    //
    //
    @Override
    public void query(final PreparedStatementCreator psc, final RowCallbackHandler rch) throws SQLException {
        this.query(psc, new RowCallbackHandlerResultSetExtractor(rch));
    }
    @Override
    public void query(final String sql, final RowCallbackHandler rch) throws SQLException {
        this.query(sql, new RowCallbackHandlerResultSetExtractor(rch));
    }
    @Override
    public void query(final String sql, final PreparedStatementSetter pss, final RowCallbackHandler rch) throws SQLException {
        this.query(sql, pss, new RowCallbackHandlerResultSetExtractor(rch));
    }
    @Override
    public void query(final String sql, final RowCallbackHandler rch, final Object... args) throws SQLException {
        this.query(sql, this.newArgPreparedStatementSetter(args), rch);
    }
    @Override
    public void query(final String sql, final Object[] args, final RowCallbackHandler rch) throws SQLException {
        this.query(sql, this.newArgPreparedStatementSetter(args), rch);
    }
    @Override
    public void query(final String sql, final SqlParameterSource paramSource, final RowCallbackHandler rch) throws SQLException {
        this.query(this.getPreparedStatementCreator(sql, paramSource), rch);
    }
    @Override
    public void query(final String sql, final Map<String, ?> paramMap, final RowCallbackHandler rch) throws SQLException {
        this.query(this.getPreparedStatementCreator(sql, new InnerMapSqlParameterSource(paramMap)), rch);
    }
    //
    //
    //
    @Override
    public <T> List<T> query(final PreparedStatementCreator psc, final RowMapper<T> rowMapper) throws SQLException {
        return this.query(psc, new RowMapperResultSetExtractor<T>(rowMapper));
    }
    @Override
    public <T> List<T> query(final String sql, final PreparedStatementSetter pss, final RowMapper<T> rowMapper) throws SQLException {
        return this.query(sql, pss, new RowMapperResultSetExtractor<T>(rowMapper));
    }
    @Override
    public <T> List<T> query(final String sql, final RowMapper<T> rowMapper, final Object... args) throws SQLException {
        return this.query(sql, args, new RowMapperResultSetExtractor<T>(rowMapper));
    }
    @Override
    public <T> List<T> query(final String sql, final Object[] args, final RowMapper<T> rowMapper) throws SQLException {
        return this.query(sql, args, new RowMapperResultSetExtractor<T>(rowMapper));
    }
    @Override
    public <T> List<T> query(final String sql, final RowMapper<T> rowMapper) throws SQLException {
        return this.query(sql, new RowMapperResultSetExtractor<T>(rowMapper));
    }
    @Override
    public <T> List<T> query(final String sql, final SqlParameterSource paramSource, final RowMapper<T> rowMapper) throws SQLException {
        return this.query(this.getPreparedStatementCreator(sql, paramSource), rowMapper);
    }
    @Override
    public <T> List<T> query(final String sql, final Map<String, ?> paramMap, final RowMapper<T> rowMapper) throws SQLException {
        return this.query(this.getPreparedStatementCreator(sql, new InnerMapSqlParameterSource(paramMap)), rowMapper);
    }
    //
    //
    //
    @Override
    public <T> List<T> queryForList(final String sql, final Class<T> elementType) throws SQLException {
        return this.query(sql, this.getBeanPropertyRowMapper(elementType));
    }
    @Override
    public <T> List<T> queryForList(final String sql, final Class<T> elementType, final Object... args) throws SQLException {
        return this.query(sql, args, this.getBeanPropertyRowMapper(elementType));
    }
    @Override
    public <T> List<T> queryForList(final String sql, final Object[] args, final Class<T> elementType) throws SQLException {
        return this.query(sql, args, this.getBeanPropertyRowMapper(elementType));
    }
    @Override
    public <T> List<T> queryForList(final String sql, final SqlParameterSource paramSource, final Class<T> elementType) throws SQLException {
        return this.query(sql, paramSource, this.getBeanPropertyRowMapper(elementType));
    }
    @Override
    public <T> List<T> queryForList(final String sql, final Map<String, ?> paramMap, final Class<T> elementType) throws SQLException {
        return this.query(sql, paramMap, this.getBeanPropertyRowMapper(elementType));
    }
    //
    //
    //
    @Override
    public <T> T queryForObject(final String sql, final RowMapper<T> rowMapper) throws SQLException {
        List<T> results = this.query(sql, rowMapper);
        return JdbcTemplate.requiredSingleResult(results);
    }
    @Override
    public <T> T queryForObject(final String sql, final RowMapper<T> rowMapper, final Object... args) throws SQLException {
        List<T> results = this.query(sql, args, new RowMapperResultSetExtractor<T>(rowMapper, 1));
        return JdbcTemplate.requiredSingleResult(results);
    }
    @Override
    public <T> T queryForObject(final String sql, final Object[] args, final RowMapper<T> rowMapper) throws SQLException {
        List<T> results = this.query(sql, args, new RowMapperResultSetExtractor<T>(rowMapper, 1));
        return JdbcTemplate.requiredSingleResult(results);
    }
    @Override
    public <T> T queryForObject(final String sql, final SqlParameterSource paramSource, final RowMapper<T> rowMapper) throws SQLException {
        List<T> results = this.query(this.getPreparedStatementCreator(sql, paramSource), rowMapper);
        return JdbcTemplate.requiredSingleResult(results);
    }
    @Override
    public <T> T queryForObject(final String sql, final Map<String, ?> paramMap, final RowMapper<T> rowMapper) throws SQLException {
        return this.queryForObject(sql, new InnerMapSqlParameterSource(paramMap), rowMapper);
    }
    @Override
    public <T> T queryForObject(final String sql, final Class<T> requiredType) throws SQLException {
        return this.queryForObject(sql, this.getBeanPropertyRowMapper(requiredType));
    }
    @Override
    public <T> T queryForObject(final String sql, final Class<T> requiredType, final Object... args) throws SQLException {
        return this.queryForObject(sql, args, this.getBeanPropertyRowMapper(requiredType));
    }
    @Override
    public <T> T queryForObject(final String sql, final Object[] args, final Class<T> requiredType) throws SQLException {
        return this.queryForObject(sql, args, this.getBeanPropertyRowMapper(requiredType));
    }
    @Override
    public <T> T queryForObject(final String sql, final SqlParameterSource paramSource, final Class<T> requiredType) throws SQLException {
        return this.queryForObject(sql, paramSource, this.getBeanPropertyRowMapper(requiredType));
    }
    @Override
    public <T> T queryForObject(final String sql, final Map<String, ?> paramMap, final Class<T> requiredType) throws SQLException {
        return this.queryForObject(sql, paramMap, this.getBeanPropertyRowMapper(requiredType));
    }
    //
    //
    //
    @Override
    public long queryForLong(final String sql) throws SQLException {
        Number number = this.queryForObject(sql, this.getSingleColumnRowMapper(Long.class));
        return number != null ? number.longValue() : 0;
    }
    @Override
    public long queryForLong(final String sql, final Object... args) throws SQLException {
        Number number = this.queryForObject(sql, args, this.getSingleColumnRowMapper(Long.class));
        return number != null ? number.longValue() : 0;
    }
    @Override
    public long queryForLong(final String sql, final SqlParameterSource paramSource) throws SQLException {
        Number number = this.queryForObject(sql, paramSource, this.getSingleColumnRowMapper(Number.class));
        return number != null ? number.longValue() : 0;
    }
    @Override
    public long queryForLong(final String sql, final Map<String, ?> paramMap) throws SQLException {
        return this.queryForLong(sql, new InnerMapSqlParameterSource(paramMap));
    }
    @Override
    public int queryForInt(final String sql) throws SQLException {
        Number number = this.queryForObject(sql, this.getSingleColumnRowMapper(Integer.class));
        return number != null ? number.intValue() : 0;
    }
    @Override
    public int queryForInt(final String sql, final Object... args) throws SQLException {
        Number number = this.queryForObject(sql, args, this.getSingleColumnRowMapper(Integer.class));
        return number != null ? number.intValue() : 0;
    }
    @Override
    public int queryForInt(final String sql, final SqlParameterSource paramSource) throws SQLException {
        Number number = this.queryForObject(sql, paramSource, this.getSingleColumnRowMapper(Number.class));
        return number != null ? number.intValue() : 0;
    }
    @Override
    public int queryForInt(final String sql, final Map<String, ?> paramMap) throws SQLException {
        return this.queryForInt(sql, new InnerMapSqlParameterSource(paramMap));
    }
    //
    //
    //
    @Override
    public Map<String, Object> queryForMap(final String sql) throws SQLException {
        return this.queryForObject(sql, this.getColumnMapRowMapper());
    }
    @Override
    public Map<String, Object> queryForMap(final String sql, final Object... args) throws SQLException {
        return this.queryForObject(sql, args, this.getColumnMapRowMapper());
    }
    @Override
    public Map<String, Object> queryForMap(final String sql, final SqlParameterSource paramSource) throws SQLException {
        return this.queryForObject(sql, paramSource, this.getColumnMapRowMapper());
    }
    @Override
    public Map<String, Object> queryForMap(final String sql, final Map<String, ?> paramMap) throws SQLException {
        return this.queryForObject(sql, paramMap, this.getColumnMapRowMapper());
    }
    @Override
    public List<Map<String, Object>> queryForList(final String sql) throws SQLException {
        return this.query(sql, this.getColumnMapRowMapper());
    }
    @Override
    public List<Map<String, Object>> queryForList(final String sql, final Object... args) throws SQLException {
        return this.query(sql, args, this.getColumnMapRowMapper());
    }
    @Override
    public List<Map<String, Object>> queryForList(final String sql, final SqlParameterSource paramSource) throws SQLException {
        return this.query(sql, paramSource, this.getColumnMapRowMapper());
    }
    @Override
    public List<Map<String, Object>> queryForList(final String sql, final Map<String, ?> paramMap) throws SQLException {
        return this.queryForList(sql, new InnerMapSqlParameterSource(paramMap));
    }
    //
    //
    //
    //    public SqlRowSet queryForRowSet(String sql) throws DataAccessException {
    //        return query(sql, new SqlRowSetResultSetExtractor());
    //    }
    //    public SqlRowSet queryForRowSet(String sql, Object... args) throws DataAccessException {
    //        return query(sql, args, new SqlRowSetResultSetExtractor());
    //    }
    //    public SqlRowSet queryForRowSet(String sql, Object[] args, int[] argTypes) throws DataAccessException {
    //        return query(sql, args, argTypes, new SqlRowSetResultSetExtractor());
    //    }
    //    public SqlRowSet queryForRowSet(String sql, SqlParameterSource paramSource) throws DataAccessException {
    //        return query(getPreparedStatementCreator(sql, paramSource), new SqlRowSetResultSetExtractor());
    //    }
    //    public SqlRowSet queryForRowSet(String sql, Map<String, ?> paramMap) throws DataAccessException {
    //        return queryForRowSet(sql, new MapSqlParameterSource(paramMap));
    //    }
    //
    //
    //
    /***/
    public int update(final PreparedStatementCreator psc, final PreparedStatementSetter pss) throws SQLException {
        Hasor.logDebug("Executing prepared SQL update");
        return this.execute(psc, new PreparedStatementCallback<Integer>() {
            @Override
            public Integer doInPreparedStatement(final PreparedStatement ps) throws SQLException {
                try {
                    if (pss != null) {
                        pss.setValues(ps);
                    }
                    int rows = ps.executeUpdate();
                    Hasor.logDebug("SQL update affected " + rows + " rows");
                    return rows;
                } finally {
                    if (pss instanceof ParameterDisposer) {
                        ((ParameterDisposer) pss).cleanupParameters();
                    }
                }
            }
        });
    }
    @Override
    public int update(final PreparedStatementCreator psc) throws SQLException {
        return this.update(psc, (PreparedStatementSetter) null);
    }
    @Override
    public int update(final String sql) throws SQLException {
        Hasor.assertIsNotNull(sql, "SQL must not be null");
        Hasor.logDebug("Executing SQL update [%s]", sql);
        //
        class UpdateStatementCallback implements StatementCallback<Integer>, SqlProvider {
            @Override
            public Integer doInStatement(final Statement stmt) throws SQLException {
                int rows = stmt.executeUpdate(sql);
                Hasor.logDebug("SQL update affected %s rows.", rows);
                return rows;
            }
            @Override
            public String getSql() {
                return sql;
            }
        }
        return this.execute(new UpdateStatementCallback());
    }
    @Override
    public int update(final String sql, final PreparedStatementSetter pss) throws SQLException {
        return this.update(new SimplePreparedStatementCreator(sql), pss);
    }
    @Override
    public int update(final String sql, final Object... args) throws SQLException {
        return this.update(sql, this.newArgPreparedStatementSetter(args));
    }
    @Override
    public int update(final String sql, final SqlParameterSource paramSource) throws SQLException {
        return this.update(this.getPreparedStatementCreator(sql, paramSource));
    }
    @Override
    public int update(final String sql, final Map<String, ?> paramMap) throws SQLException {
        return this.update(this.getPreparedStatementCreator(sql, new InnerMapSqlParameterSource(paramMap)));
    }
    //
    //
    //
    @Override
    public int[] batchUpdate(final String[] sql) throws SQLException {
        if (ArrayUtils.isEmpty(sql)) {
            throw new NullPointerException(sql + "SQL array must not be empty");
        }
        Hasor.logDebug("Executing SQL batch update of %s statements", sql.length);
        //
        class BatchUpdateStatementCallback implements StatementCallback<int[]>, SqlProvider {
            private String currSql;
            @Override
            public int[] doInStatement(final Statement stmt) throws SQLException {
                DatabaseMetaData dbmd = stmt.getConnection().getMetaData();
                int[] rowsAffected = new int[sql.length];
                if (dbmd.supportsBatchUpdates()) {
                    /*连接支持批处理*/
                    for (String sqlStmt : sql) {
                        this.currSql = sqlStmt;
                        stmt.addBatch(sqlStmt);
                    }
                    rowsAffected = stmt.executeBatch();
                } else
                    /*连接不支持批处理*/
                    for (int i = 0; i < sql.length; i++) {
                        this.currSql = sql[i];
                        if (!stmt.execute(sql[i])) {
                            rowsAffected[i] = stmt.getUpdateCount();
                        } else {
                            throw new SQLException("Invalid batch SQL statement: " + sql[i]);
                        }
                    }
                return rowsAffected;
            }
            @Override
            public String getSql() {
                return this.currSql;
            }
        }
        return this.execute(new BatchUpdateStatementCallback());
    }
    @Override
    public int[] batchUpdate(final String sql, final Map<String, ?>[] batchValues) throws SQLException {
        SqlParameterSource[] batchArgs = new SqlParameterSource[batchValues.length];
        int i = 0;
        for (Map<String, ?> values : batchValues) {
            batchArgs[i] = new InnerMapSqlParameterSource(values);
            i++;
        }
        return this.batchUpdate(sql, batchArgs);
    }
    @Override
    public int[] batchUpdate(final String sql, final SqlParameterSource[] batchArgs) throws SQLException {
        if (batchArgs.length <= 0) {
            return new int[] { 0 };
        }
        return this.batchUpdate(sql, new SqlParameterSourceBatchPreparedStatementSetter(sql, batchArgs));
    }
    @Override
    public int[] batchUpdate(String sql, final BatchPreparedStatementSetter pss) throws SQLException {
        Hasor.logDebug("Executing SQL batch update [%s].", sql);
        final ParsedSql parsedSql = ParsedSql.getParsedSql(sql);
        sql = ParsedSql.buildSql(parsedSql, null);
        //
        return this.execute(sql, new PreparedStatementCallback<int[]>() {
            @Override
            public int[] doInPreparedStatement(final PreparedStatement ps) throws SQLException {
                try {
                    int batchSize = pss.getBatchSize();
                    InterruptibleBatchPreparedStatementSetter ipss = pss instanceof InterruptibleBatchPreparedStatementSetter ? (InterruptibleBatchPreparedStatementSetter) pss : null;
                    DatabaseMetaData dbMetaData = ps.getConnection().getMetaData();
                    if (dbMetaData.supportsBatchUpdates()) {
                        for (int i = 0; i < batchSize; i++) {
                            pss.setValues(ps, i);
                            if (ipss != null && ipss.isBatchExhausted(i)) {
                                break;
                            }
                            ps.addBatch();
                        }
                        return ps.executeBatch();
                    } else {
                        List<Integer> rowsAffected = new ArrayList<Integer>();
                        for (int i = 0; i < batchSize; i++) {
                            pss.setValues(ps, i);
                            if (ipss != null && ipss.isBatchExhausted(i)) {
                                break;
                            }
                            rowsAffected.add(ps.executeUpdate());
                        }
                        int[] rowsAffectedArray = new int[rowsAffected.size()];
                        for (int i = 0; i < rowsAffectedArray.length; i++) {
                            rowsAffectedArray[i] = rowsAffected.get(i);
                        }
                        return rowsAffectedArray;
                    }
                } finally {
                    if (pss instanceof ParameterDisposer) {
                        ((ParameterDisposer) pss).cleanupParameters();
                    }
                }
            }
        });
    }
    //
    //
    //
    /** Create a new RowMapper for reading columns as key-value pairs. */
    protected RowMapper<Map<String, Object>> getColumnMapRowMapper() {
        return new ColumnMapRowMapper() {
            @Override
            protected Map<String, Object> createColumnMap(final int columnCount) {
                return JdbcTemplate.this.createResultsMap();
            }
        };
    }
    /** Create a new RowMapper for reading columns as Bean pairs. */
    protected <T> RowMapper<T> getBeanPropertyRowMapper(final Class<T> requiredType) {
        Hasor.assertIsNotNull(requiredType != null, "requiredType is null.");
        if (Map.class.isAssignableFrom(requiredType))
            return (RowMapper<T>) this.getColumnMapRowMapper();
        //
        if (requiredType.isPrimitive() || Number.class.isAssignableFrom(requiredType) || String.class.isAssignableFrom(requiredType))
            return this.getSingleColumnRowMapper(requiredType);
        //
        return new BeanPropertyRowMapper<T>(requiredType) {
            @Override
            public boolean isCaseInsensitive() {
                return JdbcTemplate.this.isResultsCaseInsensitive();
            }
        };
    }
    /** Create a new RowMapper for reading result objects from a single column.*/
    protected <T> RowMapper<T> getSingleColumnRowMapper(final Class<T> requiredType) {
        return new SingleColumnRowMapper<T>(requiredType);
    }
    //
    //
    /**创建用于保存结果集的数据Map。*/
    protected Map<String, Object> createResultsMap() {
        if (!this.isResultsCaseInsensitive())
            return new LinkedCaseInsensitiveMap<Object>();
        else
            return new LinkedHashMap<String, Object>();
    }
    /** Create a new PreparedStatementSetter.*/
    protected PreparedStatementSetter newArgPreparedStatementSetter(final Object[] args) throws SQLException {
        return new InnerArgPreparedStatementSetter(args);
    }
    /**对Statement的属性进行设置。设置 JDBC Statement 对象的 fetchSize、maxRows、Timeout等参数。*/
    protected void applyStatementSettings(final Statement stmt) throws SQLException {
        int fetchSize = this.getFetchSize();
        if (fetchSize > 0)
            stmt.setFetchSize(fetchSize);
        int maxRows = this.getMaxRows();
        if (maxRows > 0)
            stmt.setMaxRows(maxRows);
        int timeout = this.getQueryTimeout();
        if (timeout > 0)
            stmt.setQueryTimeout(timeout);
    }
    /**
     * Build a PreparedStatementCreator based on the given SQL and named parameters.
     * <p>Note: Not used for the <code>update</code> variant with generated key handling.
     */
    protected PreparedStatementCreator getPreparedStatementCreator(final String sql, final SqlParameterSource paramSource) {
        return new MapPreparedStatementCreator(sql, paramSource);
    }
    //
    /**处理潜在的 SQL 警告。当要求不忽略 SQL 警告时,检测到 SQL 警告抛出 SQL 异常。*/
    private void handleWarnings(final Statement stmt) throws SQLException {
        if (this.isIgnoreWarnings()) {
            if (Hasor.isDebugLogger()) {
                SQLWarning warningToLog = stmt.getWarnings();
                while (warningToLog != null) {
                    Hasor.logDebug("SQLWarning ignored: SQL state '%s', error code '%s', message [%s].", warningToLog.getSQLState(), warningToLog.getErrorCode(), warningToLog.getMessage());
                    warningToLog = warningToLog.getNextWarning();
                }
            }
        } else {
            SQLWarning warning = stmt.getWarnings();
            if (warning != null)
                throw new SQLException("Warning not ignored", warning);
        }
    }
    /**获取SQL文本*/
    private static String getSql(final Object sqlProvider) {
        if (sqlProvider instanceof SqlProvider)
            return ((SqlProvider) sqlProvider).getSql();
        else
            return null;
    }
    //
    /**至返回结果集中的一条数据。*/
    private static <T> T requiredSingleResult(final Collection<T> results) throws SQLException {
        int size = results != null ? results.size() : 0;
        if (size == 0)
            throw new SQLException("Empty Result");
        if (results.size() > 1)
            throw new SQLException("Incorrect column count: expected 1, actual " + size);
        return results.iterator().next();
    }
    /**获取与本地线程绑定的数据库连接,JDBC 框架会维护这个连接的事务。开发者不必关心该连接的事务管理,以及资源释放操作。*/
    private Connection newProxyConnection(final Connection target, final DataSource targetSource) {
        Hasor.assertIsNotNull(target, "Connection is null.");
        CloseSuppressingInvocationHandler handler = new CloseSuppressingInvocationHandler(target, targetSource);
        return (Connection) Proxy.newProxyInstance(ConnectionProxy.class.getClassLoader(), new Class[] { ConnectionProxy.class }, handler);
    }
    //
    //
    /**获取SQL*/
    protected static interface SqlProvider {
        public String getSql();
    }
    /**Connection 接口代理,目的是为了控制一些方法的调用。同时进行一些特殊类型的处理。*/
    private class CloseSuppressingInvocationHandler implements InvocationHandler {
        private final Connection target;
        private final DataSource targetSource;
        public CloseSuppressingInvocationHandler(final Connection target, final DataSource targetSource) {
            this.target = target;
            this.targetSource = targetSource;
        }
        @Override
        public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
            // Invocation on ConnectionProxy interface coming in...
            if (method.getName().equals("getTargetConnection"))
                // Handle getTargetConnection method: return underlying Connection.
                return this.target;
            else if (method.getName().equals("getTargetSource"))
                // Handle getTargetConnection method: return underlying DataSource.
                return this.targetSource;
            else if (method.getName().equals("equals"))
                // Only consider equal when proxies are identical.
                return proxy == args[0];
            else if (method.getName().equals("hashCode"))
                // Use hashCode of PersistenceManager proxy.
                return System.identityHashCode(proxy);
            else if (method.getName().equals("close"))
                return null;
            // Invoke method on target Connection.
            try {
                Object retVal = method.invoke(this.target, args);
                // If return value is a JDBC Statement, apply statement settings (fetch size, max rows, transaction timeout).
                if (retVal instanceof Statement)
                    JdbcTemplate.this.applyStatementSettings((Statement) retVal);
                return retVal;
            } catch (InvocationTargetException ex) {
                throw ex.getTargetException();
            }
        }
    }
    /**接口 {@link PreparedStatementCreator} 的简单实现,目的是根据 SQL 语句创建 {@link PreparedStatement}对象。*/
    private static class SimplePreparedStatementCreator implements PreparedStatementCreator, JdbcTemplate.SqlProvider {
        private final String sql;
        public SimplePreparedStatementCreator(final String sql) {
            Hasor.assertIsNotNull(sql, "SQL must not be null");
            this.sql = sql;
        }
        @Override
        public PreparedStatement createPreparedStatement(final Connection con) throws SQLException {
            return con.prepareStatement(this.sql);
        }
        @Override
        public String getSql() {
            return this.sql;
        }
    }
    /**接口 {@link CallableStatementCreator} 的简单实现,目的是根据 SQL 语句创建 {@link CallableStatement}对象。*/
    private static class SimpleCallableStatementCreator implements CallableStatementCreator, JdbcTemplate.SqlProvider {
        private final String callString;
        public SimpleCallableStatementCreator(final String callString) {
            Hasor.assertIsNotNull(callString, "Call string must not be null");
            this.callString = callString;
        }
        @Override
        public CallableStatement createCallableStatement(final Connection con) throws SQLException {
            return con.prepareCall(this.callString);
        }
        @Override
        public String getSql() {
            return this.callString;
        }
    }
    /**使用 {@link RowCallbackHandler} 类型循环处理每一行记录的适配器*/
    private static class RowCallbackHandlerResultSetExtractor implements ResultSetExtractor<Object> {
        private final RowCallbackHandler rch;
        public RowCallbackHandlerResultSetExtractor(final RowCallbackHandler rch) {
            this.rch = rch;
        }
        @Override
        public Object extractData(final ResultSet rs) throws SQLException {
            while (rs.next())
                this.rch.processRow(rs);
            return null;
        }
    }
    /**接口 {@link CallableStatementCreator} 的简单实现,目的是根据 SQL 语句创建 {@link CallableStatement}对象。*/
    private static class MapPreparedStatementCreator implements PreparedStatementCreator, ParameterDisposer, JdbcTemplate.SqlProvider {
        private ParsedSql          parsedSql   = null;
        private SqlParameterSource paramSource = null;
        //
        public MapPreparedStatementCreator(final String originalSql, final SqlParameterSource paramSource) {
            Hasor.assertIsNotNull(originalSql, "SQL must not be null");
            this.parsedSql = ParsedSql.getParsedSql(originalSql);
            this.paramSource = paramSource;
        }
        //
        @Override
        public PreparedStatement createPreparedStatement(final Connection con) throws SQLException {
            //1.根据参数信息生成最终会执行的SQL语句.
            String sqlToUse = ParsedSql.buildSql(this.parsedSql, this.paramSource);
            //2.确定参数对象
            Object[] paramArray = ParsedSql.buildSqlValues(this.parsedSql, this.paramSource);
            //3.创建PreparedStatement对象,并设置参数
            PreparedStatement statement = con.prepareStatement(sqlToUse);
            for (int i = 0; i < paramArray.length; i++)
                InnerStatementSetterUtils.setParameterValue(statement, i + 1, paramArray[i]);
            InnerStatementSetterUtils.cleanupParameters(paramArray);
            return statement;
        }
        @Override
        public String getSql() {
            return this.parsedSql.getOriginalSql();
        }
        @Override
        public void cleanupParameters() {
            if (this.paramSource instanceof ParameterDisposer)
                ((ParameterDisposer) this.paramSource).cleanupParameters();
        }
    }
    /**接口 {@link BatchPreparedStatementSetter} 的简单实现,目的是设置批量操作*/
    private static class SqlParameterSourceBatchPreparedStatementSetter implements BatchPreparedStatementSetter, ParameterDisposer {
        private ParsedSql            parsedSql = null;
        private SqlParameterSource[] batchArgs = null;
        public SqlParameterSourceBatchPreparedStatementSetter(final String sql, final SqlParameterSource[] batchArgs) {
            this.parsedSql = ParsedSql.getParsedSql(sql);
            this.batchArgs = batchArgs;
        }
        //        public String preparedSQL(int i) throws SQLException {
        //            SqlParameterSource paramSource = this.batchArgs[i];
        //            //1.根据参数信息生成最终会执行的SQL语句.
        //            String sqlText = ParsedSql.buildSql(this.parsedSql, paramSource);
        //            return sqlText;
        //        }
        @Override
        public void setValues(final PreparedStatement ps, final int index) throws SQLException {
            SqlParameterSource paramSource = this.batchArgs[index];
            //1.确定参数对象
            Object[] sqlValue = ParsedSql.buildSqlValues(this.parsedSql, paramSource);
            //2.设置参数
            int sqlColIndx = 1;
            for (Object element : sqlValue)
                InnerStatementSetterUtils.setParameterValue(ps, sqlColIndx++, element);
        }
        @Override
        public int getBatchSize() {
            return this.batchArgs.length;
        }
        @Override
        public void cleanupParameters() {
            for (SqlParameterSource batchItem : this.batchArgs)
                if (batchItem instanceof ParameterDisposer)
                    ((ParameterDisposer) batchItem).cleanupParameters();
        }
    }
}
TOP

Related Classes of net.hasor.db.jdbc.core.JdbcTemplate$RowCallbackHandlerResultSetExtractor

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.