001: /*
002: * Copyright 2002-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.jdbc.core.simple;
018:
019: import java.sql.PreparedStatement;
020: import java.sql.SQLException;
021: import java.util.List;
022: import java.util.Map;
023:
024: import javax.sql.DataSource;
025:
026: import org.springframework.dao.DataAccessException;
027: import org.springframework.jdbc.core.BatchPreparedStatementSetter;
028: import org.springframework.jdbc.core.JdbcOperations;
029: import org.springframework.jdbc.core.SqlParameterValue;
030: import org.springframework.jdbc.core.SqlTypeValue;
031: import org.springframework.jdbc.core.StatementCreatorUtils;
032: import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
033: import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
034: import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
035: import org.springframework.jdbc.core.namedparam.NamedParameterUtils;
036: import org.springframework.jdbc.core.namedparam.ParsedSql;
037: import org.springframework.jdbc.core.namedparam.SqlParameterSource;
038: import org.springframework.util.ObjectUtils;
039:
040: /**
041: * Java-5-based convenience wrapper for the classic Spring
042: * {@link org.springframework.jdbc.core.JdbcTemplate},
043: * taking advantage of varargs and autoboxing, and exposing only the most
044: * commonly required operations in order to simplify JdbcTemplate usage.
045: *
046: * <p>Use the {@link #getJdbcOperations()} method (or a straight JdbcTemplate)
047: * if you need to invoke less commonly used template methods. This includes
048: * any methods specifying SQL types, methods using less commonly used callbacks
049: * such as RowCallbackHandler, updates with PreparedStatementSetters rather than
050: * argument arrays, and stored procedures as well as batch operations.
051: *
052: * @author Rod Johnson
053: * @author Rob Harrop
054: * @author Juergen Hoeller
055: * @author Thomas Risberg
056: * @since 2.0
057: * @see ParameterizedRowMapper
058: * @see SimpleJdbcDaoSupport
059: * @see org.springframework.jdbc.core.JdbcTemplate
060: */
061: public class SimpleJdbcTemplate implements SimpleJdbcOperations {
062:
063: /** The NamedParameterJdbcTemplate that we are wrapping */
064: private final NamedParameterJdbcOperations namedParameterJdbcOperations;
065:
066: /**
067: * Create a new SimpleJdbcTemplate for the given DataSource.
068: * <p>Creates a classic Spring JdbcTemplate and wraps it.
069: * @param dataSource the JDBC DataSource to access
070: */
071: public SimpleJdbcTemplate(DataSource dataSource) {
072: this .namedParameterJdbcOperations = new NamedParameterJdbcTemplate(
073: dataSource);
074: }
075:
076: /**
077: * Create a new SimpleJdbcTemplate for the given classic Spring JdbcTemplate.
078: * @param classicJdbcTemplate the classic Spring JdbcTemplate to wrap
079: */
080: public SimpleJdbcTemplate(JdbcOperations classicJdbcTemplate) {
081: this .namedParameterJdbcOperations = new NamedParameterJdbcTemplate(
082: classicJdbcTemplate);
083: }
084:
085: /**
086: * Create a new SimpleJdbcTemplate for the given Spring NamedParameterJdbcTemplate.
087: * @param namedParameterJdbcTemplate the Spring NamedParameterJdbcTemplate to wrap
088: */
089: public SimpleJdbcTemplate(
090: NamedParameterJdbcOperations namedParameterJdbcTemplate) {
091: this .namedParameterJdbcOperations = namedParameterJdbcTemplate;
092: }
093:
094: /**
095: * Expose the classic Spring JdbcTemplate to allow invocation of
096: * less commonly used methods.
097: */
098: public JdbcOperations getJdbcOperations() {
099: return this .namedParameterJdbcOperations.getJdbcOperations();
100: }
101:
102: /**
103: * Expose the Spring NamedParameterJdbcTemplate to allow invocation of
104: * less commonly used methods.
105: */
106: public NamedParameterJdbcOperations getNamedParameterJdbcOperations() {
107: return this .namedParameterJdbcOperations;
108: }
109:
110: public int queryForInt(String sql, Map args)
111: throws DataAccessException {
112: return getNamedParameterJdbcOperations().queryForInt(sql, args);
113: }
114:
115: public int queryForInt(String sql, SqlParameterSource args)
116: throws DataAccessException {
117: return getNamedParameterJdbcOperations().queryForInt(sql, args);
118: }
119:
120: public int queryForInt(String sql, Object... args)
121: throws DataAccessException {
122: return (ObjectUtils.isEmpty(args) ? getJdbcOperations()
123: .queryForInt(sql) : getJdbcOperations().queryForInt(
124: sql, getArguments(args)));
125: }
126:
127: public long queryForLong(String sql, Map args)
128: throws DataAccessException {
129: return getNamedParameterJdbcOperations()
130: .queryForLong(sql, args);
131: }
132:
133: public long queryForLong(String sql, SqlParameterSource args)
134: throws DataAccessException {
135: return getNamedParameterJdbcOperations()
136: .queryForLong(sql, args);
137: }
138:
139: public long queryForLong(String sql, Object... args)
140: throws DataAccessException {
141: return (ObjectUtils.isEmpty(args) ? getJdbcOperations()
142: .queryForLong(sql) : getJdbcOperations().queryForLong(
143: sql, getArguments(args)));
144: }
145:
146: @SuppressWarnings("unchecked")
147: public <T> T queryForObject(String sql, Class<T> requiredType,
148: Map args) throws DataAccessException {
149: return (T) getNamedParameterJdbcOperations().queryForObject(
150: sql, args, requiredType);
151: }
152:
153: @SuppressWarnings("unchecked")
154: public <T> T queryForObject(String sql, Class<T> requiredType,
155: SqlParameterSource args) throws DataAccessException {
156: return (T) getNamedParameterJdbcOperations().queryForObject(
157: sql, args, requiredType);
158: }
159:
160: @SuppressWarnings("unchecked")
161: public <T> T queryForObject(String sql, Class<T> requiredType,
162: Object... args) throws DataAccessException {
163: return (T) (ObjectUtils.isEmpty(args) ? getJdbcOperations()
164: .queryForObject(sql, requiredType)
165: : getJdbcOperations().queryForObject(sql,
166: getArguments(args), requiredType));
167: }
168:
169: @SuppressWarnings("unchecked")
170: public <T> T queryForObject(String sql,
171: ParameterizedRowMapper<T> rm, Map args)
172: throws DataAccessException {
173: return (T) getNamedParameterJdbcOperations().queryForObject(
174: sql, args, rm);
175: }
176:
177: @SuppressWarnings("unchecked")
178: public <T> T queryForObject(String sql,
179: ParameterizedRowMapper<T> rm, SqlParameterSource args)
180: throws DataAccessException {
181: return (T) getNamedParameterJdbcOperations().queryForObject(
182: sql, args, rm);
183: }
184:
185: @SuppressWarnings("unchecked")
186: public <T> T queryForObject(String sql,
187: ParameterizedRowMapper<T> rm, Object... args)
188: throws DataAccessException {
189: return (T) (ObjectUtils.isEmpty(args) ? getJdbcOperations()
190: .queryForObject(sql, rm) : getJdbcOperations()
191: .queryForObject(sql, getArguments(args), rm));
192: }
193:
194: @SuppressWarnings("unchecked")
195: public <T> List<T> query(String sql, ParameterizedRowMapper<T> rm,
196: Map args) throws DataAccessException {
197: return (List<T>) getNamedParameterJdbcOperations().query(sql,
198: args, rm);
199: }
200:
201: @SuppressWarnings("unchecked")
202: public <T> List<T> query(String sql, ParameterizedRowMapper<T> rm,
203: SqlParameterSource args) throws DataAccessException {
204: return (List<T>) getNamedParameterJdbcOperations().query(sql,
205: args, rm);
206: }
207:
208: @SuppressWarnings("unchecked")
209: public <T> List<T> query(String sql, ParameterizedRowMapper<T> rm,
210: Object... args) throws DataAccessException {
211: return (List<T>) (ObjectUtils.isEmpty(args) ? getJdbcOperations()
212: .query(sql, rm)
213: : getJdbcOperations()
214: .query(sql, getArguments(args), rm));
215: }
216:
217: @SuppressWarnings("unchecked")
218: public Map<String, Object> queryForMap(String sql, Map args)
219: throws DataAccessException {
220: return getNamedParameterJdbcOperations().queryForMap(sql, args);
221: }
222:
223: @SuppressWarnings("unchecked")
224: public Map<String, Object> queryForMap(String sql,
225: SqlParameterSource args) throws DataAccessException {
226: return getNamedParameterJdbcOperations().queryForMap(sql, args);
227: }
228:
229: @SuppressWarnings("unchecked")
230: public Map<String, Object> queryForMap(String sql, Object... args)
231: throws DataAccessException {
232: return (ObjectUtils.isEmpty(args) ? getJdbcOperations()
233: .queryForMap(sql) : getJdbcOperations().queryForMap(
234: sql, getArguments(args)));
235: }
236:
237: @SuppressWarnings("unchecked")
238: public List<Map<String, Object>> queryForList(String sql, Map args)
239: throws DataAccessException {
240: return getNamedParameterJdbcOperations()
241: .queryForList(sql, args);
242: }
243:
244: @SuppressWarnings("unchecked")
245: public List<Map<String, Object>> queryForList(String sql,
246: SqlParameterSource args) throws DataAccessException {
247: return getNamedParameterJdbcOperations()
248: .queryForList(sql, args);
249: }
250:
251: @SuppressWarnings("unchecked")
252: public List<Map<String, Object>> queryForList(String sql,
253: Object... args) throws DataAccessException {
254: return (ObjectUtils.isEmpty(args) ? getJdbcOperations()
255: .queryForList(sql) : getJdbcOperations().queryForList(
256: sql, getArguments(args)));
257: }
258:
259: public int update(String sql, Map args) throws DataAccessException {
260: return getNamedParameterJdbcOperations().update(sql, args);
261: }
262:
263: public int update(String sql, SqlParameterSource args)
264: throws DataAccessException {
265: return getNamedParameterJdbcOperations().update(sql, args);
266: }
267:
268: public int update(String sql, Object... args)
269: throws DataAccessException {
270: return (ObjectUtils.isEmpty(args) ? getJdbcOperations().update(
271: sql) : getJdbcOperations().update(sql,
272: getArguments(args)));
273: }
274:
275: public int[] batchUpdate(String sql, List<Object[]> batchArgs) {
276: return doExecuteBatchUpdate(sql, batchArgs, new int[0]);
277: }
278:
279: public int[] batchUpdate(String sql, List<Object[]> batchArgs,
280: int[] argTypes) {
281: return doExecuteBatchUpdate(sql, batchArgs, argTypes);
282: }
283:
284: public int[] batchUpdate(String sql, Map[] batchValues) {
285: SqlParameterSource[] batchArgs = new SqlParameterSource[batchValues.length];
286: int i = 0;
287: for (Map values : batchValues) {
288: batchArgs[i] = new MapSqlParameterSource(values);
289: i++;
290: }
291: return doExecuteBatchUpdateWithNamedParameters(sql, batchArgs);
292: }
293:
294: public int[] batchUpdate(String sql, SqlParameterSource[] batchArgs) {
295: return doExecuteBatchUpdateWithNamedParameters(sql, batchArgs);
296: }
297:
298: private int[] doExecuteBatchUpdate(String sql,
299: final List<Object[]> batchValues, final int[] columnTypes) {
300: return getJdbcOperations().batchUpdate(sql,
301: new BatchPreparedStatementSetter() {
302:
303: public void setValues(PreparedStatement ps, int i)
304: throws SQLException {
305: Object[] values = batchValues.get(i);
306: doSetStatementParameters(values, ps,
307: columnTypes);
308: }
309:
310: public int getBatchSize() {
311: return batchValues.size();
312: }
313: });
314: }
315:
316: private int[] doExecuteBatchUpdateWithNamedParameters(String sql,
317: final SqlParameterSource[] batchArgs) {
318: if (batchArgs.length <= 0) {
319: return new int[] { 0 };
320: }
321: final ParsedSql parsedSql = NamedParameterUtils
322: .parseSqlStatement(sql);
323: String sqlToUse = NamedParameterUtils
324: .substituteNamedParameters(parsedSql, batchArgs[0]);
325: return getJdbcOperations().batchUpdate(sqlToUse,
326: new BatchPreparedStatementSetter() {
327:
328: public void setValues(PreparedStatement ps, int i)
329: throws SQLException {
330: Object[] values = NamedParameterUtils
331: .buildValueArray(parsedSql,
332: batchArgs[i], null);
333: int[] columnTypes = NamedParameterUtils
334: .buildSqlTypeArray(parsedSql,
335: batchArgs[i]);
336: doSetStatementParameters(values, ps,
337: columnTypes);
338: }
339:
340: public int getBatchSize() {
341: return batchArgs.length;
342: }
343: });
344: }
345:
346: private void doSetStatementParameters(Object[] values,
347: PreparedStatement ps, int[] columnTypes)
348: throws SQLException {
349: int colIndex = 0;
350: for (Object value : values) {
351: colIndex++;
352: if (value instanceof SqlParameterValue) {
353: SqlParameterValue paramValue = (SqlParameterValue) value;
354: StatementCreatorUtils.setParameterValue(ps, colIndex,
355: paramValue, paramValue.getValue());
356: } else {
357: int colType;
358: if (columnTypes == null
359: || columnTypes.length < colIndex) {
360: colType = SqlTypeValue.TYPE_UNKNOWN;
361: } else {
362: colType = columnTypes[colIndex - 1];
363: }
364: StatementCreatorUtils.setParameterValue(ps, colIndex,
365: colType, value);
366: }
367: }
368: }
369:
370: /**
371: * Considers an Object array passed into a varargs parameter as
372: * collection of arguments rather than as single argument.
373: */
374: private Object[] getArguments(Object[] varArgs) {
375: if (varArgs.length == 1 && varArgs[0] instanceof Object[]) {
376: return (Object[]) varArgs[0];
377: } else {
378: return varArgs;
379: }
380: }
381:
382: }
|