/* * 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.data.jdbc.core; import net.hasor.core.Hasor; import net.hasor.core.utils.IOUtils; import net.hasor.core.utils.ResourcesUtils; import net.hasor.data.jdbc.*; import net.hasor.data.jdbc.mapper.BeanPropertyRowMapper; import net.hasor.data.jdbc.mapper.ColumnMapRowMapper; import net.hasor.data.jdbc.mapper.SingleColumnRowMapper; import net.hasor.data.jdbc.paramer.MapSqlParameterSource; import net.hasor.data.jdbc.result.LinkedCaseInsensitiveMap; import javax.sql.DataSource; import java.io.*; import java.nio.charset.Charset; import java.sql.*; import java.util.*; /** * 数据库操作模板方法。 * @version : 2013-10-12 * @author 赵永春 (zyc@byshell.org) */ public class JdbcTemplate extends JdbcConnection implements JdbcOperations { /*是否忽略出现的 SQL 警告*/ private boolean ignoreWarnings = true; /*当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() { super(); } /** * 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) { super(dataSource); } /** * Construct a new JdbcTemplate, given a Connection to obtain connections from. * <p>Note: This will not trigger initialization of the exception translator. * @param conn the JDBC Connection */ public JdbcTemplate(final Connection conn) { super(conn); } // // // public boolean isIgnoreWarnings() { return this.ignoreWarnings; } public void setIgnoreWarnings(final boolean ignoreWarnings) { this.ignoreWarnings = ignoreWarnings; } 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()); } // // @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) { if (stmt != null) { logger.error(stmt.toString()); } throw ex; } finally { if (stmt != null) { 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 (logger.isDebugEnabled()) { String sql = JdbcTemplate.getSql(psc); logger.debug("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) { if (ps != null) { logger.error(ps.toString()); } throw ex; } finally { if (psc instanceof ParameterDisposer) { ((ParameterDisposer) psc).cleanupParameters(); } if (ps != null) { 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 (logger.isDebugEnabled()) { String sql = JdbcTemplate.getSql(csc); logger.debug("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) { String sqlString = JdbcTemplate.getSql(action); throw new SQLException("CallableStatementCallback SQL :" + sqlString, ex); } finally { if (csc instanceof ParameterDisposer) { ((ParameterDisposer) csc).cleanupParameters(); } if (cs != null) { 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 MapSqlParameterSource(paramMap)), action); } // // // @Override public boolean execute(final String sql) throws SQLException { if (logger.isDebugEnabled()) { logger.debug("Executing SQL statement [{}].", 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."); if (logger.isDebugEnabled()) { logger.debug("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 { if (rs != null) { 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."); if (logger.isDebugEnabled()) { logger.debug("Executing SQL query [{}].", 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 MapSqlParameterSource(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 MapSqlParameterSource(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 MapSqlParameterSource(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 MapSqlParameterSource(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 MapSqlParameterSource(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 MapSqlParameterSource(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 MapSqlParameterSource(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 { if (logger.isDebugEnabled()) { logger.debug("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(); if (logger.isDebugEnabled()) { logger.debug("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"); if (logger.isDebugEnabled()) { logger.debug("Executing SQL update [{}]", sql); } // class UpdateStatementCallback implements StatementCallback<Integer>, SqlProvider { @Override public Integer doInStatement(final Statement stmt) throws SQLException { int rows = stmt.executeUpdate(sql); if (logger.isDebugEnabled()) { logger.debug("SQL update affected {} 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 MapSqlParameterSource(paramMap))); } // // // @Override public int[] batchUpdate(final String[] sql) throws SQLException { if (sql == null || sql.length == 0) { throw new NullPointerException("SQL array must not be empty"); } if (logger.isDebugEnabled()) { logger.debug("Executing SQL batch update of {} 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 MapSqlParameterSource(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 { if (logger.isDebugEnabled()) { logger.debug("Executing SQL batch update [{}].", sql); } final 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); } /** * 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); } /* Map of original SQL String to ParsedSql representation */ private final Map<String, ParsedSql> parsedSqlCache = new HashMap<String, ParsedSql>(); /*Obtain a parsed representation of the given SQL statement.*/ protected ParsedSql getParsedSql(String originalSql) { synchronized (this.parsedSqlCache) { ParsedSql parsedSql = (ParsedSql) this.parsedSqlCache.get(originalSql); if (parsedSql == null) { parsedSql = ParsedSql.getParsedSql(originalSql); this.parsedSqlCache.put(originalSql, parsedSql); } return parsedSql; } } // /**处理潜在的 SQL 警告。当要求不忽略 SQL 警告时,检测到 SQL 警告抛出 SQL 异常。*/ private void handleWarnings(final Statement stmt) throws SQLException { if (this.isIgnoreWarnings()) { if (logger.isDebugEnabled()) { SQLWarning warningToLog = stmt.getWarnings(); while (warningToLog != null) { logger.debug("SQLWarning ignored: SQL state '{}', error code '{}', message [{}].", 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(); } // // /**获取SQL*/ protected static interface SqlProvider { public String getSql(); } /**接口 {@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 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 = 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 class SqlParameterSourceBatchPreparedStatementSetter implements BatchPreparedStatementSetter, ParameterDisposer { private ParsedSql parsedSql = null; private SqlParameterSource[] batchArgs = null; public SqlParameterSourceBatchPreparedStatementSetter(final String sql, final SqlParameterSource[] batchArgs) { this.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(); } } }