Source Code Cross Referenced for JdbcTemplate.java in  » J2EE » spring-framework-2.0.6 » org » springframework » jdbc » core » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » J2EE » spring framework 2.0.6 » org.springframework.jdbc.core 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2002-2007 the original author or authors.
0003:         *
0004:         * Licensed under the Apache License, Version 2.0 (the "License");
0005:         * you may not use this file except in compliance with the License.
0006:         * You may obtain a copy of the License at
0007:         *
0008:         *      http://www.apache.org/licenses/LICENSE-2.0
0009:         *
0010:         * Unless required by applicable law or agreed to in writing, software
0011:         * distributed under the License is distributed on an "AS IS" BASIS,
0012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013:         * See the License for the specific language governing permissions and
0014:         * limitations under the License.
0015:         */
0016:
0017:        package org.springframework.jdbc.core;
0018:
0019:        import java.lang.reflect.InvocationHandler;
0020:        import java.lang.reflect.InvocationTargetException;
0021:        import java.lang.reflect.Method;
0022:        import java.lang.reflect.Proxy;
0023:        import java.sql.CallableStatement;
0024:        import java.sql.Connection;
0025:        import java.sql.PreparedStatement;
0026:        import java.sql.ResultSet;
0027:        import java.sql.SQLException;
0028:        import java.sql.SQLWarning;
0029:        import java.sql.Statement;
0030:        import java.util.ArrayList;
0031:        import java.util.HashMap;
0032:        import java.util.List;
0033:        import java.util.Map;
0034:
0035:        import javax.sql.DataSource;
0036:
0037:        import org.springframework.dao.DataAccessException;
0038:        import org.springframework.dao.InvalidDataAccessApiUsageException;
0039:        import org.springframework.dao.support.DataAccessUtils;
0040:        import org.springframework.jdbc.SQLWarningException;
0041:        import org.springframework.jdbc.datasource.ConnectionProxy;
0042:        import org.springframework.jdbc.datasource.DataSourceUtils;
0043:        import org.springframework.jdbc.support.JdbcAccessor;
0044:        import org.springframework.jdbc.support.JdbcUtils;
0045:        import org.springframework.jdbc.support.KeyHolder;
0046:        import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;
0047:        import org.springframework.jdbc.support.rowset.SqlRowSet;
0048:        import org.springframework.util.Assert;
0049:
0050:        /**
0051:         * <b>This is the central class in the JDBC core package.</b>
0052:         * It simplifies the use of JDBC and helps to avoid common errors.
0053:         * It executes core JDBC workflow, leaving application code to provide SQL
0054:         * and extract results. This class executes SQL queries or updates, initiating
0055:         * iteration over ResultSets and catching JDBC exceptions and translating
0056:         * them to the generic, more informative exception hierarchy defined in the
0057:         * <code>org.springframework.dao</code> package.
0058:         *
0059:         * <p>Code using this class need only implement callback interfaces, giving
0060:         * them a clearly defined contract. The {@link PreparedStatementCreator} callback
0061:         * interface creates a prepared statement given a Connection, providing SQL and
0062:         * any necessary parameters. The {@link ResultSetExtractor} interface extracts
0063:         * values from a ResultSet. See also {@link PreparedStatementSetter} and
0064:         * {@link RowMapper} for two popular alternative callback interfaces.
0065:         *
0066:         * <p>Can be used within a service implementation via direct instantiation
0067:         * with a DataSource reference, or get prepared in an application context
0068:         * and given to services as bean reference. Note: The DataSource should
0069:         * always be configured as a bean in the application context, in the first case
0070:         * given to the service directly, in the second case to the prepared template.
0071:         *
0072:         * <p>Because this class is parameterizable by the callback interfaces and
0073:         * the {@link org.springframework.jdbc.support.SQLExceptionTranslator}
0074:         * interface, there should be no need to subclass it.
0075:         *
0076:         * <p>All operations performed by this class are logged at debug level.
0077:         *
0078:         * @author Rod Johnson
0079:         * @author Juergen Hoeller
0080:         * @author Thomas Risberg
0081:         * @since May 3, 2001
0082:         * @see PreparedStatementCreator
0083:         * @see PreparedStatementSetter
0084:         * @see CallableStatementCreator
0085:         * @see PreparedStatementCallback
0086:         * @see CallableStatementCallback
0087:         * @see ResultSetExtractor
0088:         * @see RowCallbackHandler
0089:         * @see RowMapper
0090:         * @see org.springframework.jdbc.support.SQLExceptionTranslator
0091:         */
0092:        public class JdbcTemplate extends JdbcAccessor implements 
0093:                JdbcOperations {
0094:
0095:            /** Custom NativeJdbcExtractor */
0096:            private NativeJdbcExtractor nativeJdbcExtractor;
0097:
0098:            /** If this variable is false, we will throw exceptions on SQL warnings */
0099:            private boolean ignoreWarnings = true;
0100:
0101:            /**
0102:             * If this variable is set to a non-zero value, it will be used for setting the
0103:             * fetchSize property on statements used for query processing.
0104:             */
0105:            private int fetchSize = 0;
0106:
0107:            /**
0108:             * If this variable is set to a non-zero value, it will be used for setting the
0109:             * maxRows property on statements used for query processing.
0110:             */
0111:            private int maxRows = 0;
0112:
0113:            /**
0114:             * If this variable is set to a non-zero value, it will be used for setting the
0115:             * queryTimeout property on statements used for query processing.
0116:             */
0117:            private int queryTimeout = 0;
0118:
0119:            /**
0120:             * If this variable is set to true then all results checking will be bypassed for any
0121:             * callable statement processing.  This can be used to avoid a bug in some older Oracle
0122:             * JDBC drivers like 10.1.0.2.
0123:             */
0124:            private boolean skipResultsProcessing = false;
0125:
0126:            /**
0127:             * Construct a new JdbcTemplate for bean usage.
0128:             * <p>Note: The DataSource has to be set before using the instance.
0129:             * @see #setDataSource
0130:             */
0131:            public JdbcTemplate() {
0132:            }
0133:
0134:            /**
0135:             * Construct a new JdbcTemplate, given a DataSource to obtain connections from.
0136:             * <p>Note: This will not trigger initialization of the exception translator.
0137:             * @param dataSource the JDBC DataSource to obtain connections from
0138:             */
0139:            public JdbcTemplate(DataSource dataSource) {
0140:                setDataSource(dataSource);
0141:                afterPropertiesSet();
0142:            }
0143:
0144:            /**
0145:             * Construct a new JdbcTemplate, given a DataSource to obtain connections from.
0146:             * <p>Note: Depending on the "lazyInit" flag, initialization of the exception translator
0147:             * will be triggered.
0148:             * @param dataSource the JDBC DataSource to obtain connections from
0149:             * @param lazyInit whether to lazily initialize the SQLExceptionTranslator
0150:             */
0151:            public JdbcTemplate(DataSource dataSource, boolean lazyInit) {
0152:                setDataSource(dataSource);
0153:                setLazyInit(lazyInit);
0154:                afterPropertiesSet();
0155:            }
0156:
0157:            /**
0158:             * Set a NativeJdbcExtractor to extract native JDBC objects from wrapped handles.
0159:             * Useful if native Statement and/or ResultSet handles are expected for casting
0160:             * to database-specific implementation classes, but a connection pool that wraps
0161:             * JDBC objects is used (note: <i>any</i> pool will return wrapped Connections).
0162:             */
0163:            public void setNativeJdbcExtractor(NativeJdbcExtractor extractor) {
0164:                this .nativeJdbcExtractor = extractor;
0165:            }
0166:
0167:            /**
0168:             * Return the current NativeJdbcExtractor implementation.
0169:             */
0170:            public NativeJdbcExtractor getNativeJdbcExtractor() {
0171:                return this .nativeJdbcExtractor;
0172:            }
0173:
0174:            /**
0175:             * Set whether or not we want to ignore SQLWarnings.
0176:             * <p>Default is "true", swallowing and logging all warnings. Switch this flag
0177:             * to "false" to make the JdbcTemplate throw a SQLWarningException instead.
0178:             * @see java.sql.SQLWarning
0179:             * @see org.springframework.jdbc.SQLWarningException
0180:             * @see #handleWarnings
0181:             */
0182:            public void setIgnoreWarnings(boolean ignoreWarnings) {
0183:                this .ignoreWarnings = ignoreWarnings;
0184:            }
0185:
0186:            /**
0187:             * Return whether or not we ignore SQLWarnings.
0188:             */
0189:            public boolean isIgnoreWarnings() {
0190:                return this .ignoreWarnings;
0191:            }
0192:
0193:            /**
0194:             * Set the fetch size for this JdbcTemplate. This is important for processing
0195:             * large result sets: Setting this higher than the default value will increase
0196:             * processing speed at the cost of memory consumption; setting this lower can
0197:             * avoid transferring row data that will never be read by the application.
0198:             * <p>Default is 0, indicating to use the JDBC driver's default.
0199:             * @see java.sql.Statement#setFetchSize
0200:             */
0201:            public void setFetchSize(int fetchSize) {
0202:                this .fetchSize = fetchSize;
0203:            }
0204:
0205:            /**
0206:             * Return the fetch size specified for this JdbcTemplate.
0207:             */
0208:            public int getFetchSize() {
0209:                return this .fetchSize;
0210:            }
0211:
0212:            /**
0213:             * Set the maximum number of rows for this JdbcTemplate. This is important
0214:             * for processing subsets of large result sets, avoiding to read and hold
0215:             * the entire result set in the database or in the JDBC driver if we're
0216:             * never interested in the entire result in the first place (for example,
0217:             * when performing searches that might return a large number of matches).
0218:             * <p>Default is 0, indicating to use the JDBC driver's default.
0219:             * @see java.sql.Statement#setMaxRows
0220:             */
0221:            public void setMaxRows(int maxRows) {
0222:                this .maxRows = maxRows;
0223:            }
0224:
0225:            /**
0226:             * Return the maximum number of rows specified for this JdbcTemplate.
0227:             */
0228:            public int getMaxRows() {
0229:                return this .maxRows;
0230:            }
0231:
0232:            /**
0233:             * Set the query timeout for statements that this JdbcTemplate executes.
0234:             * <p>Default is 0, indicating to use the JDBC driver's default.
0235:             * <p>Note: Any timeout specified here will be overridden by the remaining
0236:             * transaction timeout when executing within a transaction that has a
0237:             * timeout specified at the transaction level.
0238:             * @see java.sql.Statement#setQueryTimeout
0239:             */
0240:            public void setQueryTimeout(int queryTimeout) {
0241:                this .queryTimeout = queryTimeout;
0242:            }
0243:
0244:            /**
0245:             * Return the query timeout for statements that this JdbcTemplate executes.
0246:             */
0247:            public int getQueryTimeout() {
0248:                return this .queryTimeout;
0249:            }
0250:
0251:            /**
0252:             * Set whether results processing should be skipped.  Can be used to optimize callable
0253:             * statement processing when we know that no results are being passed back - the processing
0254:             * of out parameter will still take place.  This can be used to avoid a bug in some older
0255:             * Oracle JDBC drivers like 10.1.0.2.
0256:             */
0257:            public void setSkipResultsProcessing(boolean skipResultsProcessing) {
0258:                this .skipResultsProcessing = skipResultsProcessing;
0259:            }
0260:
0261:            /**
0262:             * Return whether results processing should be skipped.
0263:             */
0264:            public boolean isSkipResultsProcessing() {
0265:                return this .skipResultsProcessing;
0266:            }
0267:
0268:            //-------------------------------------------------------------------------
0269:            // Methods dealing with a plain java.sql.Connection
0270:            //-------------------------------------------------------------------------
0271:
0272:            public Object execute(ConnectionCallback action)
0273:                    throws DataAccessException {
0274:                Assert.notNull(action, "Callback object must not be null");
0275:
0276:                Connection con = DataSourceUtils.getConnection(getDataSource());
0277:                try {
0278:                    Connection conToUse = con;
0279:                    if (this .nativeJdbcExtractor != null) {
0280:                        // Extract native JDBC Connection, castable to OracleConnection or the like.
0281:                        conToUse = this .nativeJdbcExtractor
0282:                                .getNativeConnection(con);
0283:                    } else {
0284:                        // Create close-suppressing Connection proxy, also preparing returned Statements.
0285:                        conToUse = createConnectionProxy(con);
0286:                    }
0287:                    return action.doInConnection(conToUse);
0288:                } catch (SQLException ex) {
0289:                    // Release Connection early, to avoid potential connection pool deadlock
0290:                    // in the case when the exception translator hasn't been initialized yet.
0291:                    DataSourceUtils.releaseConnection(con, getDataSource());
0292:                    con = null;
0293:                    throw getExceptionTranslator().translate(
0294:                            "ConnectionCallback", getSql(action), ex);
0295:                } finally {
0296:                    DataSourceUtils.releaseConnection(con, getDataSource());
0297:                }
0298:            }
0299:
0300:            /**
0301:             * Create a close-suppressing proxy for the given JDBC Connection.
0302:             * Called by the <code>execute</code> method.
0303:             * <p>The proxy also prepares returned JDBC Statements, applying
0304:             * statement settings such as fetch size, max rows, and query timeout.
0305:             * @param con the JDBC Connection to create a proxy for
0306:             * @return the Connection proxy
0307:             * @see java.sql.Connection#close()
0308:             * @see #execute(ConnectionCallback)
0309:             * @see #applyStatementSettings
0310:             */
0311:            protected Connection createConnectionProxy(Connection con) {
0312:                return (Connection) Proxy.newProxyInstance(
0313:                        ConnectionProxy.class.getClassLoader(),
0314:                        new Class[] { ConnectionProxy.class },
0315:                        new CloseSuppressingInvocationHandler(con));
0316:            }
0317:
0318:            //-------------------------------------------------------------------------
0319:            // Methods dealing with static SQL (java.sql.Statement)
0320:            //-------------------------------------------------------------------------
0321:
0322:            public Object execute(StatementCallback action)
0323:                    throws DataAccessException {
0324:                Assert.notNull(action, "Callback object must not be null");
0325:
0326:                Connection con = DataSourceUtils.getConnection(getDataSource());
0327:                Statement stmt = null;
0328:                try {
0329:                    Connection conToUse = con;
0330:                    if (this .nativeJdbcExtractor != null
0331:                            && this .nativeJdbcExtractor
0332:                                    .isNativeConnectionNecessaryForNativeStatements()) {
0333:                        conToUse = this .nativeJdbcExtractor
0334:                                .getNativeConnection(con);
0335:                    }
0336:                    stmt = conToUse.createStatement();
0337:                    applyStatementSettings(stmt);
0338:                    Statement stmtToUse = stmt;
0339:                    if (this .nativeJdbcExtractor != null) {
0340:                        stmtToUse = this .nativeJdbcExtractor
0341:                                .getNativeStatement(stmt);
0342:                    }
0343:                    Object result = action.doInStatement(stmtToUse);
0344:                    handleWarnings(stmt.getWarnings());
0345:                    return result;
0346:                } catch (SQLException ex) {
0347:                    // Release Connection early, to avoid potential connection pool deadlock
0348:                    // in the case when the exception translator hasn't been initialized yet.
0349:                    JdbcUtils.closeStatement(stmt);
0350:                    stmt = null;
0351:                    DataSourceUtils.releaseConnection(con, getDataSource());
0352:                    con = null;
0353:                    throw getExceptionTranslator().translate(
0354:                            "StatementCallback", getSql(action), ex);
0355:                } finally {
0356:                    JdbcUtils.closeStatement(stmt);
0357:                    DataSourceUtils.releaseConnection(con, getDataSource());
0358:                }
0359:            }
0360:
0361:            public void execute(final String sql) throws DataAccessException {
0362:                if (logger.isDebugEnabled()) {
0363:                    logger.debug("Executing SQL statement [" + sql + "]");
0364:                }
0365:
0366:                class ExecuteStatementCallback implements  StatementCallback,
0367:                        SqlProvider {
0368:                    public Object doInStatement(Statement stmt)
0369:                            throws SQLException {
0370:                        stmt.execute(sql);
0371:                        return null;
0372:                    }
0373:
0374:                    public String getSql() {
0375:                        return sql;
0376:                    }
0377:                }
0378:                execute(new ExecuteStatementCallback());
0379:            }
0380:
0381:            public Object query(final String sql, final ResultSetExtractor rse)
0382:                    throws DataAccessException {
0383:                Assert.notNull(sql, "SQL must not be null");
0384:                Assert.notNull(rse, "ResultSetExtractor must not be null");
0385:                if (logger.isDebugEnabled()) {
0386:                    logger.debug("Executing SQL query [" + sql + "]");
0387:                }
0388:
0389:                class QueryStatementCallback implements  StatementCallback,
0390:                        SqlProvider {
0391:                    public Object doInStatement(Statement stmt)
0392:                            throws SQLException {
0393:                        ResultSet rs = null;
0394:                        try {
0395:                            rs = stmt.executeQuery(sql);
0396:                            ResultSet rsToUse = rs;
0397:                            if (nativeJdbcExtractor != null) {
0398:                                rsToUse = nativeJdbcExtractor
0399:                                        .getNativeResultSet(rs);
0400:                            }
0401:                            return rse.extractData(rsToUse);
0402:                        } finally {
0403:                            JdbcUtils.closeResultSet(rs);
0404:                        }
0405:                    }
0406:
0407:                    public String getSql() {
0408:                        return sql;
0409:                    }
0410:                }
0411:                return execute(new QueryStatementCallback());
0412:            }
0413:
0414:            public void query(String sql, RowCallbackHandler rch)
0415:                    throws DataAccessException {
0416:                query(sql, new RowCallbackHandlerResultSetExtractor(rch));
0417:            }
0418:
0419:            public List query(String sql, RowMapper rowMapper)
0420:                    throws DataAccessException {
0421:                return (List) query(sql, new RowMapperResultSetExtractor(
0422:                        rowMapper));
0423:            }
0424:
0425:            public Map queryForMap(String sql) throws DataAccessException {
0426:                return (Map) queryForObject(sql, getColumnMapRowMapper());
0427:            }
0428:
0429:            public Object queryForObject(String sql, RowMapper rowMapper)
0430:                    throws DataAccessException {
0431:                List results = query(sql, rowMapper);
0432:                return DataAccessUtils.requiredSingleResult(results);
0433:            }
0434:
0435:            public Object queryForObject(String sql, Class requiredType)
0436:                    throws DataAccessException {
0437:                return queryForObject(sql,
0438:                        getSingleColumnRowMapper(requiredType));
0439:            }
0440:
0441:            public long queryForLong(String sql) throws DataAccessException {
0442:                Number number = (Number) queryForObject(sql, Long.class);
0443:                return (number != null ? number.longValue() : 0);
0444:            }
0445:
0446:            public int queryForInt(String sql) throws DataAccessException {
0447:                Number number = (Number) queryForObject(sql, Integer.class);
0448:                return (number != null ? number.intValue() : 0);
0449:            }
0450:
0451:            public List queryForList(String sql, Class elementType)
0452:                    throws DataAccessException {
0453:                return query(sql, getSingleColumnRowMapper(elementType));
0454:            }
0455:
0456:            public List queryForList(String sql) throws DataAccessException {
0457:                return query(sql, getColumnMapRowMapper());
0458:            }
0459:
0460:            public SqlRowSet queryForRowSet(String sql)
0461:                    throws DataAccessException {
0462:                return (SqlRowSet) query(sql, new SqlRowSetResultSetExtractor());
0463:            }
0464:
0465:            public int update(final String sql) throws DataAccessException {
0466:                Assert.notNull(sql, "SQL must not be null");
0467:                if (logger.isDebugEnabled()) {
0468:                    logger.debug("Executing SQL update [" + sql + "]");
0469:                }
0470:
0471:                class UpdateStatementCallback implements  StatementCallback,
0472:                        SqlProvider {
0473:                    public Object doInStatement(Statement stmt)
0474:                            throws SQLException {
0475:                        int rows = stmt.executeUpdate(sql);
0476:                        if (logger.isDebugEnabled()) {
0477:                            logger.debug("SQL update affected " + rows
0478:                                    + " rows");
0479:                        }
0480:                        return new Integer(rows);
0481:                    }
0482:
0483:                    public String getSql() {
0484:                        return sql;
0485:                    }
0486:                }
0487:                return ((Integer) execute(new UpdateStatementCallback()))
0488:                        .intValue();
0489:            }
0490:
0491:            public int[] batchUpdate(final String[] sql)
0492:                    throws DataAccessException {
0493:                Assert.notEmpty(sql, "SQL array must not be empty");
0494:                if (logger.isDebugEnabled()) {
0495:                    logger.debug("Executing SQL batch update of " + sql.length
0496:                            + " statements");
0497:                }
0498:
0499:                class BatchUpdateStatementCallback implements 
0500:                        StatementCallback, SqlProvider {
0501:                    private String currSql;
0502:
0503:                    public Object doInStatement(Statement stmt)
0504:                            throws SQLException, DataAccessException {
0505:                        int[] rowsAffected = new int[sql.length];
0506:                        if (JdbcUtils
0507:                                .supportsBatchUpdates(stmt.getConnection())) {
0508:                            for (int i = 0; i < sql.length; i++) {
0509:                                this .currSql = sql[i];
0510:                                stmt.addBatch(sql[i]);
0511:                            }
0512:                            rowsAffected = stmt.executeBatch();
0513:                        } else {
0514:                            for (int i = 0; i < sql.length; i++) {
0515:                                this .currSql = sql[i];
0516:                                if (!stmt.execute(sql[i])) {
0517:                                    rowsAffected[i] = stmt.getUpdateCount();
0518:                                } else {
0519:                                    throw new InvalidDataAccessApiUsageException(
0520:                                            "Invalid batch SQL statement: "
0521:                                                    + sql[i]);
0522:                                }
0523:                            }
0524:                        }
0525:                        return rowsAffected;
0526:                    }
0527:
0528:                    public String getSql() {
0529:                        return currSql;
0530:                    }
0531:                }
0532:                return (int[]) execute(new BatchUpdateStatementCallback());
0533:            }
0534:
0535:            //-------------------------------------------------------------------------
0536:            // Methods dealing with prepared statements
0537:            //-------------------------------------------------------------------------
0538:
0539:            public Object execute(PreparedStatementCreator psc,
0540:                    PreparedStatementCallback action)
0541:                    throws DataAccessException {
0542:
0543:                Assert
0544:                        .notNull(psc,
0545:                                "PreparedStatementCreator must not be null");
0546:                Assert.notNull(action, "Callback object must not be null");
0547:                if (logger.isDebugEnabled()) {
0548:                    String sql = getSql(psc);
0549:                    logger.debug("Executing prepared SQL statement"
0550:                            + (sql != null ? " [" + sql + "]" : ""));
0551:                }
0552:
0553:                Connection con = DataSourceUtils.getConnection(getDataSource());
0554:                PreparedStatement ps = null;
0555:                try {
0556:                    Connection conToUse = con;
0557:                    if (this .nativeJdbcExtractor != null
0558:                            && this .nativeJdbcExtractor
0559:                                    .isNativeConnectionNecessaryForNativePreparedStatements()) {
0560:                        conToUse = this .nativeJdbcExtractor
0561:                                .getNativeConnection(con);
0562:                    }
0563:                    ps = psc.createPreparedStatement(conToUse);
0564:                    applyStatementSettings(ps);
0565:                    PreparedStatement psToUse = ps;
0566:                    if (this .nativeJdbcExtractor != null) {
0567:                        psToUse = this .nativeJdbcExtractor
0568:                                .getNativePreparedStatement(ps);
0569:                    }
0570:                    Object result = action.doInPreparedStatement(psToUse);
0571:                    handleWarnings(ps.getWarnings());
0572:                    return result;
0573:                } catch (SQLException ex) {
0574:                    // Release Connection early, to avoid potential connection pool deadlock
0575:                    // in the case when the exception translator hasn't been initialized yet.
0576:                    if (psc instanceof  ParameterDisposer) {
0577:                        ((ParameterDisposer) psc).cleanupParameters();
0578:                    }
0579:                    String sql = getSql(psc);
0580:                    psc = null;
0581:                    JdbcUtils.closeStatement(ps);
0582:                    ps = null;
0583:                    DataSourceUtils.releaseConnection(con, getDataSource());
0584:                    con = null;
0585:                    throw getExceptionTranslator().translate(
0586:                            "PreparedStatementCallback", sql, ex);
0587:                } finally {
0588:                    if (psc instanceof  ParameterDisposer) {
0589:                        ((ParameterDisposer) psc).cleanupParameters();
0590:                    }
0591:                    JdbcUtils.closeStatement(ps);
0592:                    DataSourceUtils.releaseConnection(con, getDataSource());
0593:                }
0594:            }
0595:
0596:            public Object execute(String sql, PreparedStatementCallback action)
0597:                    throws DataAccessException {
0598:                return execute(new SimplePreparedStatementCreator(sql), action);
0599:            }
0600:
0601:            /**
0602:             * Query using a prepared statement, allowing for a PreparedStatementCreator
0603:             * and a PreparedStatementSetter. Most other query methods use this method,
0604:             * but application code will always work with either a creator or a setter.
0605:             * @param psc Callback handler that can create a PreparedStatement given a
0606:             * Connection
0607:             * @param pss object that knows how to set values on the prepared statement.
0608:             * If this is null, the SQL will be assumed to contain no bind parameters.
0609:             * @param rse object that will extract results.
0610:             * @return an arbitrary result object, as returned by the ResultSetExtractor
0611:             * @throws DataAccessException if there is any problem
0612:             */
0613:            public Object query(PreparedStatementCreator psc,
0614:                    final PreparedStatementSetter pss,
0615:                    final ResultSetExtractor rse) throws DataAccessException {
0616:
0617:                Assert.notNull(rse, "ResultSetExtractor must not be null");
0618:                logger.debug("Executing prepared SQL query");
0619:
0620:                return execute(psc, new PreparedStatementCallback() {
0621:                    public Object doInPreparedStatement(PreparedStatement ps)
0622:                            throws SQLException {
0623:                        ResultSet rs = null;
0624:                        try {
0625:                            if (pss != null) {
0626:                                pss.setValues(ps);
0627:                            }
0628:                            rs = ps.executeQuery();
0629:                            ResultSet rsToUse = rs;
0630:                            if (nativeJdbcExtractor != null) {
0631:                                rsToUse = nativeJdbcExtractor
0632:                                        .getNativeResultSet(rs);
0633:                            }
0634:                            return rse.extractData(rsToUse);
0635:                        } finally {
0636:                            JdbcUtils.closeResultSet(rs);
0637:                            if (pss instanceof  ParameterDisposer) {
0638:                                ((ParameterDisposer) pss).cleanupParameters();
0639:                            }
0640:                        }
0641:                    }
0642:                });
0643:            }
0644:
0645:            public Object query(PreparedStatementCreator psc,
0646:                    ResultSetExtractor rse) throws DataAccessException {
0647:                return query(psc, null, rse);
0648:            }
0649:
0650:            public Object query(String sql, PreparedStatementSetter pss,
0651:                    ResultSetExtractor rse) throws DataAccessException {
0652:                return query(new SimplePreparedStatementCreator(sql), pss, rse);
0653:            }
0654:
0655:            public Object query(String sql, Object[] args, int[] argTypes,
0656:                    ResultSetExtractor rse) throws DataAccessException {
0657:                return query(sql, new ArgTypePreparedStatementSetter(args,
0658:                        argTypes), rse);
0659:            }
0660:
0661:            public Object query(String sql, Object[] args,
0662:                    ResultSetExtractor rse) throws DataAccessException {
0663:                return query(sql, new ArgPreparedStatementSetter(args), rse);
0664:            }
0665:
0666:            public void query(PreparedStatementCreator psc,
0667:                    RowCallbackHandler rch) throws DataAccessException {
0668:                query(psc, new RowCallbackHandlerResultSetExtractor(rch));
0669:            }
0670:
0671:            public void query(String sql, PreparedStatementSetter pss,
0672:                    RowCallbackHandler rch) throws DataAccessException {
0673:                query(sql, pss, new RowCallbackHandlerResultSetExtractor(rch));
0674:            }
0675:
0676:            public void query(String sql, Object[] args, int[] argTypes,
0677:                    RowCallbackHandler rch) throws DataAccessException {
0678:                query(sql, new ArgTypePreparedStatementSetter(args, argTypes),
0679:                        rch);
0680:            }
0681:
0682:            public void query(String sql, Object[] args, RowCallbackHandler rch)
0683:                    throws DataAccessException {
0684:                query(sql, new ArgPreparedStatementSetter(args), rch);
0685:            }
0686:
0687:            public List query(PreparedStatementCreator psc, RowMapper rowMapper)
0688:                    throws DataAccessException {
0689:                return (List) query(psc, new RowMapperResultSetExtractor(
0690:                        rowMapper));
0691:            }
0692:
0693:            public List query(String sql, PreparedStatementSetter pss,
0694:                    RowMapper rowMapper) throws DataAccessException {
0695:                return (List) query(sql, pss, new RowMapperResultSetExtractor(
0696:                        rowMapper));
0697:            }
0698:
0699:            public List query(String sql, Object[] args, int[] argTypes,
0700:                    RowMapper rowMapper) throws DataAccessException {
0701:                return (List) query(sql, args, argTypes,
0702:                        new RowMapperResultSetExtractor(rowMapper));
0703:            }
0704:
0705:            public List query(String sql, Object[] args, RowMapper rowMapper)
0706:                    throws DataAccessException {
0707:                return (List) query(sql, args, new RowMapperResultSetExtractor(
0708:                        rowMapper));
0709:            }
0710:
0711:            public Object queryForObject(String sql, Object[] args,
0712:                    int[] argTypes, RowMapper rowMapper)
0713:                    throws DataAccessException {
0714:
0715:                List results = (List) query(sql, args, argTypes,
0716:                        new RowMapperResultSetExtractor(rowMapper, 1));
0717:                return DataAccessUtils.requiredSingleResult(results);
0718:            }
0719:
0720:            public Object queryForObject(String sql, Object[] args,
0721:                    RowMapper rowMapper) throws DataAccessException {
0722:                List results = (List) query(sql, args,
0723:                        new RowMapperResultSetExtractor(rowMapper, 1));
0724:                return DataAccessUtils.requiredSingleResult(results);
0725:            }
0726:
0727:            public Object queryForObject(String sql, Object[] args,
0728:                    int[] argTypes, Class requiredType)
0729:                    throws DataAccessException {
0730:
0731:                return queryForObject(sql, args, argTypes,
0732:                        getSingleColumnRowMapper(requiredType));
0733:            }
0734:
0735:            public Object queryForObject(String sql, Object[] args,
0736:                    Class requiredType) throws DataAccessException {
0737:                return queryForObject(sql, args,
0738:                        getSingleColumnRowMapper(requiredType));
0739:            }
0740:
0741:            public Map queryForMap(String sql, Object[] args, int[] argTypes)
0742:                    throws DataAccessException {
0743:                return (Map) queryForObject(sql, args, argTypes,
0744:                        getColumnMapRowMapper());
0745:            }
0746:
0747:            public Map queryForMap(String sql, Object[] args)
0748:                    throws DataAccessException {
0749:                return (Map) queryForObject(sql, args, getColumnMapRowMapper());
0750:            }
0751:
0752:            public long queryForLong(String sql, Object[] args, int[] argTypes)
0753:                    throws DataAccessException {
0754:                Number number = (Number) queryForObject(sql, args, argTypes,
0755:                        Long.class);
0756:                return (number != null ? number.longValue() : 0);
0757:            }
0758:
0759:            public long queryForLong(String sql, Object[] args)
0760:                    throws DataAccessException {
0761:                Number number = (Number) queryForObject(sql, args, Long.class);
0762:                return (number != null ? number.longValue() : 0);
0763:            }
0764:
0765:            public int queryForInt(String sql, Object[] args, int[] argTypes)
0766:                    throws DataAccessException {
0767:                Number number = (Number) queryForObject(sql, args, argTypes,
0768:                        Integer.class);
0769:                return (number != null ? number.intValue() : 0);
0770:            }
0771:
0772:            public int queryForInt(String sql, Object[] args)
0773:                    throws DataAccessException {
0774:                Number number = (Number) queryForObject(sql, args,
0775:                        Integer.class);
0776:                return (number != null ? number.intValue() : 0);
0777:            }
0778:
0779:            public List queryForList(String sql, Object[] args, int[] argTypes,
0780:                    Class elementType) throws DataAccessException {
0781:                return query(sql, args, argTypes,
0782:                        getSingleColumnRowMapper(elementType));
0783:            }
0784:
0785:            public List queryForList(String sql, Object[] args,
0786:                    Class elementType) throws DataAccessException {
0787:                return query(sql, args, getSingleColumnRowMapper(elementType));
0788:            }
0789:
0790:            public List queryForList(String sql, Object[] args, int[] argTypes)
0791:                    throws DataAccessException {
0792:                return query(sql, args, argTypes, getColumnMapRowMapper());
0793:            }
0794:
0795:            public List queryForList(String sql, Object[] args)
0796:                    throws DataAccessException {
0797:                return query(sql, args, getColumnMapRowMapper());
0798:            }
0799:
0800:            public SqlRowSet queryForRowSet(String sql, Object[] args,
0801:                    int[] argTypes) throws DataAccessException {
0802:                return (SqlRowSet) query(sql, args, argTypes,
0803:                        new SqlRowSetResultSetExtractor());
0804:            }
0805:
0806:            public SqlRowSet queryForRowSet(String sql, Object[] args)
0807:                    throws DataAccessException {
0808:                return (SqlRowSet) query(sql, args,
0809:                        new SqlRowSetResultSetExtractor());
0810:            }
0811:
0812:            protected int update(final PreparedStatementCreator psc,
0813:                    final PreparedStatementSetter pss)
0814:                    throws DataAccessException {
0815:
0816:                logger.debug("Executing prepared SQL update");
0817:
0818:                Integer result = (Integer) execute(psc,
0819:                        new PreparedStatementCallback() {
0820:                            public Object doInPreparedStatement(
0821:                                    PreparedStatement ps) throws SQLException {
0822:                                try {
0823:                                    if (pss != null) {
0824:                                        pss.setValues(ps);
0825:                                    }
0826:                                    int rows = ps.executeUpdate();
0827:                                    if (logger.isDebugEnabled()) {
0828:                                        logger.debug("SQL update affected "
0829:                                                + rows + " rows");
0830:                                    }
0831:                                    return new Integer(rows);
0832:                                } finally {
0833:                                    if (pss instanceof  ParameterDisposer) {
0834:                                        ((ParameterDisposer) pss)
0835:                                                .cleanupParameters();
0836:                                    }
0837:                                }
0838:                            }
0839:                        });
0840:                return result.intValue();
0841:            }
0842:
0843:            public int update(PreparedStatementCreator psc)
0844:                    throws DataAccessException {
0845:                return update(psc, (PreparedStatementSetter) null);
0846:            }
0847:
0848:            public int update(final PreparedStatementCreator psc,
0849:                    final KeyHolder generatedKeyHolder)
0850:                    throws DataAccessException {
0851:
0852:                Assert
0853:                        .notNull(generatedKeyHolder,
0854:                                "KeyHolder must not be null");
0855:                logger
0856:                        .debug("Executing SQL update and returning generated keys");
0857:
0858:                Integer result = (Integer) execute(psc,
0859:                        new PreparedStatementCallback() {
0860:                            public Object doInPreparedStatement(
0861:                                    PreparedStatement ps) throws SQLException {
0862:                                int rows = ps.executeUpdate();
0863:                                List generatedKeys = generatedKeyHolder
0864:                                        .getKeyList();
0865:                                generatedKeys.clear();
0866:                                ResultSet keys = ps.getGeneratedKeys();
0867:                                if (keys != null) {
0868:                                    try {
0869:                                        RowMapper rowMapper = getColumnMapRowMapper();
0870:                                        RowMapperResultSetExtractor rse = new RowMapperResultSetExtractor(
0871:                                                rowMapper, 1);
0872:                                        generatedKeys.addAll((List) rse
0873:                                                .extractData(keys));
0874:                                    } finally {
0875:                                        JdbcUtils.closeResultSet(keys);
0876:                                    }
0877:                                }
0878:                                if (logger.isDebugEnabled()) {
0879:                                    logger.debug("SQL update affected " + rows
0880:                                            + " rows and returned "
0881:                                            + generatedKeys.size() + " keys");
0882:                                }
0883:                                return new Integer(rows);
0884:                            }
0885:                        });
0886:                return result.intValue();
0887:            }
0888:
0889:            public int update(String sql, PreparedStatementSetter pss)
0890:                    throws DataAccessException {
0891:                return update(new SimplePreparedStatementCreator(sql), pss);
0892:            }
0893:
0894:            public int update(String sql, Object[] args, int[] argTypes)
0895:                    throws DataAccessException {
0896:                return update(sql, new ArgTypePreparedStatementSetter(args,
0897:                        argTypes));
0898:            }
0899:
0900:            public int update(String sql, Object[] args)
0901:                    throws DataAccessException {
0902:                return update(sql, new ArgPreparedStatementSetter(args));
0903:            }
0904:
0905:            public int[] batchUpdate(String sql,
0906:                    final BatchPreparedStatementSetter pss)
0907:                    throws DataAccessException {
0908:                if (logger.isDebugEnabled()) {
0909:                    logger.debug("Executing SQL batch update [" + sql + "]");
0910:                }
0911:
0912:                return (int[]) execute(sql, new PreparedStatementCallback() {
0913:                    public Object doInPreparedStatement(PreparedStatement ps)
0914:                            throws SQLException {
0915:                        try {
0916:                            int batchSize = pss.getBatchSize();
0917:                            InterruptibleBatchPreparedStatementSetter ipss = (pss instanceof  InterruptibleBatchPreparedStatementSetter ? (InterruptibleBatchPreparedStatementSetter) pss
0918:                                    : null);
0919:                            if (JdbcUtils.supportsBatchUpdates(ps
0920:                                    .getConnection())) {
0921:                                for (int i = 0; i < batchSize; i++) {
0922:                                    pss.setValues(ps, i);
0923:                                    if (ipss != null
0924:                                            && ipss.isBatchExhausted(i)) {
0925:                                        break;
0926:                                    }
0927:                                    ps.addBatch();
0928:                                }
0929:                                return ps.executeBatch();
0930:                            } else {
0931:                                List rowsAffected = new ArrayList();
0932:                                for (int i = 0; i < batchSize; i++) {
0933:                                    pss.setValues(ps, i);
0934:                                    if (ipss != null
0935:                                            && ipss.isBatchExhausted(i)) {
0936:                                        break;
0937:                                    }
0938:                                    rowsAffected.add(new Integer(ps
0939:                                            .executeUpdate()));
0940:                                }
0941:                                int[] rowsAffectedArray = new int[rowsAffected
0942:                                        .size()];
0943:                                for (int i = 0; i < rowsAffectedArray.length; i++) {
0944:                                    rowsAffectedArray[i] = ((Integer) rowsAffected
0945:                                            .get(i)).intValue();
0946:                                }
0947:                                return rowsAffectedArray;
0948:                            }
0949:                        } finally {
0950:                            if (pss instanceof  ParameterDisposer) {
0951:                                ((ParameterDisposer) pss).cleanupParameters();
0952:                            }
0953:                        }
0954:                    }
0955:                });
0956:            }
0957:
0958:            //-------------------------------------------------------------------------
0959:            // Methods dealing with callable statements
0960:            //-------------------------------------------------------------------------
0961:
0962:            public Object execute(CallableStatementCreator csc,
0963:                    CallableStatementCallback action)
0964:                    throws DataAccessException {
0965:
0966:                Assert
0967:                        .notNull(csc,
0968:                                "CallableStatementCreator must not be null");
0969:                Assert.notNull(action, "Callback object must not be null");
0970:                if (logger.isDebugEnabled()) {
0971:                    String sql = getSql(csc);
0972:                    logger.debug("Calling stored procedure"
0973:                            + (sql != null ? " [" + sql + "]" : ""));
0974:                }
0975:
0976:                Connection con = DataSourceUtils.getConnection(getDataSource());
0977:                CallableStatement cs = null;
0978:                try {
0979:                    Connection conToUse = con;
0980:                    if (this .nativeJdbcExtractor != null) {
0981:                        conToUse = this .nativeJdbcExtractor
0982:                                .getNativeConnection(con);
0983:                    }
0984:                    cs = csc.createCallableStatement(conToUse);
0985:                    applyStatementSettings(cs);
0986:                    CallableStatement csToUse = cs;
0987:                    if (this .nativeJdbcExtractor != null) {
0988:                        csToUse = this .nativeJdbcExtractor
0989:                                .getNativeCallableStatement(cs);
0990:                    }
0991:                    Object result = action.doInCallableStatement(csToUse);
0992:                    handleWarnings(cs.getWarnings());
0993:                    return result;
0994:                } catch (SQLException ex) {
0995:                    // Release Connection early, to avoid potential connection pool deadlock
0996:                    // in the case when the exception translator hasn't been initialized yet.
0997:                    if (csc instanceof  ParameterDisposer) {
0998:                        ((ParameterDisposer) csc).cleanupParameters();
0999:                    }
1000:                    String sql = getSql(csc);
1001:                    csc = null;
1002:                    JdbcUtils.closeStatement(cs);
1003:                    cs = null;
1004:                    DataSourceUtils.releaseConnection(con, getDataSource());
1005:                    con = null;
1006:                    throw getExceptionTranslator().translate(
1007:                            "CallableStatementCallback", sql, ex);
1008:                } finally {
1009:                    if (csc instanceof  ParameterDisposer) {
1010:                        ((ParameterDisposer) csc).cleanupParameters();
1011:                    }
1012:                    JdbcUtils.closeStatement(cs);
1013:                    DataSourceUtils.releaseConnection(con, getDataSource());
1014:                }
1015:            }
1016:
1017:            public Object execute(String callString,
1018:                    CallableStatementCallback action)
1019:                    throws DataAccessException {
1020:                return execute(new SimpleCallableStatementCreator(callString),
1021:                        action);
1022:            }
1023:
1024:            public Map call(CallableStatementCreator csc,
1025:                    final List declaredParameters) throws DataAccessException {
1026:                return (Map) execute(csc, new CallableStatementCallback() {
1027:                    public Object doInCallableStatement(CallableStatement cs)
1028:                            throws SQLException {
1029:                        boolean retVal = cs.execute();
1030:                        int updateCount = cs.getUpdateCount();
1031:                        if (logger.isDebugEnabled()) {
1032:                            logger
1033:                                    .debug("CallableStatement.execute() returned '"
1034:                                            + retVal + "'");
1035:                            logger
1036:                                    .debug("CallableStatement.getUpdateCount() returned "
1037:                                            + updateCount);
1038:                        }
1039:                        Map returnedResults = new HashMap();
1040:                        if (retVal || updateCount != -1) {
1041:                            returnedResults.putAll(extractReturnedResultSets(
1042:                                    cs, declaredParameters, updateCount));
1043:                        }
1044:                        returnedResults.putAll(extractOutputParameters(cs,
1045:                                declaredParameters));
1046:                        return returnedResults;
1047:                    }
1048:                });
1049:            }
1050:
1051:            /**
1052:             * Extract returned ResultSets from the completed stored procedure.
1053:             * @param cs JDBC wrapper for the stored procedure
1054:             * @param parameters Parameter list for the stored procedure
1055:             * @return Map that contains returned results
1056:             */
1057:            protected Map extractReturnedResultSets(CallableStatement cs,
1058:                    List parameters, int updateCount) throws SQLException {
1059:
1060:                Map returnedResults = new HashMap();
1061:                int rsIndex = 0;
1062:                boolean moreResults;
1063:                if (!skipResultsProcessing) {
1064:                    do {
1065:                        if (updateCount == -1) {
1066:                            Object param = null;
1067:                            if (parameters != null
1068:                                    && parameters.size() > rsIndex) {
1069:                                param = parameters.get(rsIndex);
1070:                            }
1071:                            if (param instanceof  SqlReturnResultSet) {
1072:                                SqlReturnResultSet rsParam = (SqlReturnResultSet) param;
1073:                                returnedResults.putAll(processResultSet(cs
1074:                                        .getResultSet(), rsParam));
1075:                            } else {
1076:                                logger
1077:                                        .warn("Results returned from stored procedure but a corresponding "
1078:                                                + "SqlOutParameter/SqlReturnResultSet parameter was not declared");
1079:                            }
1080:                            rsIndex++;
1081:                        }
1082:                        moreResults = cs.getMoreResults();
1083:                        updateCount = cs.getUpdateCount();
1084:                        if (logger.isDebugEnabled()) {
1085:                            logger
1086:                                    .debug("CallableStatement.getUpdateCount() returned "
1087:                                            + updateCount);
1088:                        }
1089:                    } while (moreResults || updateCount != -1);
1090:                }
1091:                return returnedResults;
1092:            }
1093:
1094:            /**
1095:             * Extract output parameters from the completed stored procedure.
1096:             * @param cs JDBC wrapper for the stored procedure
1097:             * @param parameters parameter list for the stored procedure
1098:             * @return parameters to the stored procedure
1099:             * @return Map that contains returned results
1100:             */
1101:            protected Map extractOutputParameters(CallableStatement cs,
1102:                    List parameters) throws SQLException {
1103:                Map returnedResults = new HashMap();
1104:                int sqlColIndex = 1;
1105:                for (int i = 0; i < parameters.size(); i++) {
1106:                    Object param = parameters.get(i);
1107:                    if (param instanceof  SqlOutParameter) {
1108:                        SqlOutParameter outParam = (SqlOutParameter) param;
1109:                        if (outParam.isReturnTypeSupported()) {
1110:                            Object out = outParam.getSqlReturnType()
1111:                                    .getTypeValue(cs, sqlColIndex,
1112:                                            outParam.getSqlType(),
1113:                                            outParam.getTypeName());
1114:                            returnedResults.put(outParam.getName(), out);
1115:                        } else {
1116:                            Object out = cs.getObject(sqlColIndex);
1117:                            if (out instanceof  ResultSet) {
1118:                                if (outParam.isResultSetSupported()) {
1119:                                    returnedResults.putAll(processResultSet(
1120:                                            (ResultSet) out, outParam));
1121:                                } else {
1122:                                    logger
1123:                                            .warn("ResultSet returned from stored procedure but no corresponding SqlOutParameter "
1124:                                                    + "with a ResultSetExtractor/RowCallbackHandler/RowMapper declared");
1125:                                    returnedResults
1126:                                            .put(outParam.getName(),
1127:                                                    "ResultSet was returned but not processed");
1128:                                }
1129:                            } else {
1130:                                returnedResults.put(outParam.getName(), out);
1131:                            }
1132:                        }
1133:                    }
1134:                    if (!(param instanceof  SqlReturnResultSet)) {
1135:                        sqlColIndex++;
1136:                    }
1137:                }
1138:                return returnedResults;
1139:            }
1140:
1141:            /**
1142:             * Process the given ResultSet from a stored procedure.
1143:             * @param rs the ResultSet to process
1144:             * @param param the corresponding stored procedure parameter
1145:             * @return Map that contains returned results
1146:             */
1147:            protected Map processResultSet(ResultSet rs,
1148:                    ResultSetSupportingSqlParameter param) throws SQLException {
1149:                Map returnedResults = new HashMap();
1150:                try {
1151:                    ResultSet rsToUse = rs;
1152:                    if (this .nativeJdbcExtractor != null) {
1153:                        rsToUse = this .nativeJdbcExtractor
1154:                                .getNativeResultSet(rs);
1155:                    }
1156:                    if (param.getRowMapper() != null) {
1157:                        RowMapper rowMapper = param.getRowMapper();
1158:                        Object result = (new RowMapperResultSetExtractor(
1159:                                rowMapper)).extractData(rsToUse);
1160:                        returnedResults.put(param.getName(), result);
1161:                    } else if (param.getRowCallbackHandler() != null) {
1162:                        RowCallbackHandler rch = param.getRowCallbackHandler();
1163:                        (new RowCallbackHandlerResultSetExtractor(rch))
1164:                                .extractData(rsToUse);
1165:                        returnedResults
1166:                                .put(param.getName(),
1167:                                        "ResultSet returned from stored procedure was processed");
1168:                    } else if (param.getResultSetExtractor() != null) {
1169:                        Object result = param.getResultSetExtractor()
1170:                                .extractData(rsToUse);
1171:                        returnedResults.put(param.getName(), result);
1172:                    }
1173:                } finally {
1174:                    JdbcUtils.closeResultSet(rs);
1175:                }
1176:                return returnedResults;
1177:            }
1178:
1179:            //-------------------------------------------------------------------------
1180:            // Implementation hooks and helper methods
1181:            //-------------------------------------------------------------------------
1182:
1183:            /**
1184:             * Create a new RowMapper for reading columns as key-value pairs.
1185:             * @return the RowMapper to use
1186:             * @see ColumnMapRowMapper
1187:             */
1188:            protected RowMapper getColumnMapRowMapper() {
1189:                return new ColumnMapRowMapper();
1190:            }
1191:
1192:            /**
1193:             * Create a new RowMapper for reading result objects from a single column.
1194:             * @param requiredType the type that each result object is expected to match
1195:             * @return the RowMapper to use
1196:             * @see SingleColumnRowMapper
1197:             */
1198:            protected RowMapper getSingleColumnRowMapper(Class requiredType) {
1199:                return new SingleColumnRowMapper(requiredType);
1200:            }
1201:
1202:            /**
1203:             * Prepare the given JDBC Statement (or PreparedStatement or CallableStatement),
1204:             * applying statement settings such as fetch size, max rows, and query timeout.
1205:             * @param stmt the JDBC Statement to prepare
1206:             * @throws SQLException if thrown by JDBC API
1207:             * @see #setFetchSize
1208:             * @see #setMaxRows
1209:             * @see #setQueryTimeout
1210:             * @see org.springframework.jdbc.datasource.DataSourceUtils#applyTransactionTimeout
1211:             */
1212:            protected void applyStatementSettings(Statement stmt)
1213:                    throws SQLException {
1214:                int fetchSize = getFetchSize();
1215:                if (fetchSize > 0) {
1216:                    stmt.setFetchSize(fetchSize);
1217:                }
1218:                int maxRows = getMaxRows();
1219:                if (maxRows > 0) {
1220:                    stmt.setMaxRows(maxRows);
1221:                }
1222:                DataSourceUtils.applyTimeout(stmt, getDataSource(),
1223:                        getQueryTimeout());
1224:            }
1225:
1226:            /**
1227:             * Throw an SQLWarningException if we're not ignoring warnings,
1228:             * else log the warnings (at debug level).
1229:             * @param warning the warnings object from the current statement.
1230:             * May be <code>null</code>, in which case this method does nothing.
1231:             * @throws SQLWarningException if not ignoring warnings
1232:             * @see org.springframework.jdbc.SQLWarningException
1233:             */
1234:            protected void handleWarnings(SQLWarning warning)
1235:                    throws SQLWarningException {
1236:                if (warning != null) {
1237:                    if (isIgnoreWarnings()) {
1238:                        if (logger.isDebugEnabled()) {
1239:                            SQLWarning warningToLog = warning;
1240:                            while (warningToLog != null) {
1241:                                logger.debug("SQLWarning ignored: SQL state '"
1242:                                        + warningToLog.getSQLState()
1243:                                        + "', error code '"
1244:                                        + warningToLog.getErrorCode()
1245:                                        + "', message ["
1246:                                        + warningToLog.getMessage() + "]");
1247:                                warningToLog = warningToLog.getNextWarning();
1248:                            }
1249:                        }
1250:                    } else {
1251:                        throw new SQLWarningException("Warning not ignored",
1252:                                warning);
1253:                    }
1254:                }
1255:            }
1256:
1257:            /**
1258:             * Determine SQL from potential provider object.
1259:             * @param sqlProvider object that's potentially a SqlProvider
1260:             * @return the SQL string, or <code>null</code>
1261:             * @see SqlProvider
1262:             */
1263:            private static String getSql(Object sqlProvider) {
1264:                if (sqlProvider instanceof  SqlProvider) {
1265:                    return ((SqlProvider) sqlProvider).getSql();
1266:                } else {
1267:                    return null;
1268:                }
1269:            }
1270:
1271:            /**
1272:             * Invocation handler that suppresses close calls on JDBC COnnections.
1273:             * Also prepares returned Statement (Prepared/CallbackStatement) objects.
1274:             * @see java.sql.Connection#close()
1275:             */
1276:            private class CloseSuppressingInvocationHandler implements 
1277:                    InvocationHandler {
1278:
1279:                private final Connection target;
1280:
1281:                public CloseSuppressingInvocationHandler(Connection target) {
1282:                    this .target = target;
1283:                }
1284:
1285:                public Object invoke(Object proxy, Method method, Object[] args)
1286:                        throws Throwable {
1287:                    // Invocation on ConnectionProxy interface coming in...
1288:
1289:                    if (method.getName().equals("getTargetConnection")) {
1290:                        // Handle getTargetConnection method: return underlying Connection.
1291:                        return this .target;
1292:                    } else if (method.getName().equals("equals")) {
1293:                        // Only consider equal when proxies are identical.
1294:                        return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
1295:                    } else if (method.getName().equals("hashCode")) {
1296:                        // Use hashCode of PersistenceManager proxy.
1297:                        return new Integer(hashCode());
1298:                    } else if (method.getName().equals("close")) {
1299:                        // Handle close method: suppress, not valid.
1300:                        return null;
1301:                    }
1302:
1303:                    // Invoke method on target Connection.
1304:                    try {
1305:                        Object retVal = method.invoke(this .target, args);
1306:
1307:                        // If return value is a JDBC Statement, apply statement settings
1308:                        // (fetch size, max rows, transaction timeout).
1309:                        if (retVal instanceof  Statement) {
1310:                            applyStatementSettings(((Statement) retVal));
1311:                        }
1312:
1313:                        return retVal;
1314:                    } catch (InvocationTargetException ex) {
1315:                        throw ex.getTargetException();
1316:                    }
1317:                }
1318:            }
1319:
1320:            /**
1321:             * Simple adapter for PreparedStatementCreator, allowing to use a plain SQL statement.
1322:             */
1323:            private static class SimplePreparedStatementCreator implements 
1324:                    PreparedStatementCreator, SqlProvider {
1325:
1326:                private final String sql;
1327:
1328:                public SimplePreparedStatementCreator(String sql) {
1329:                    Assert.notNull(sql, "SQL must not be null");
1330:                    this .sql = sql;
1331:                }
1332:
1333:                public PreparedStatement createPreparedStatement(Connection con)
1334:                        throws SQLException {
1335:                    return con.prepareStatement(this .sql);
1336:                }
1337:
1338:                public String getSql() {
1339:                    return this .sql;
1340:                }
1341:            }
1342:
1343:            /**
1344:             * Simple adapter for CallableStatementCreator, allowing to use a plain SQL statement.
1345:             */
1346:            private static class SimpleCallableStatementCreator implements 
1347:                    CallableStatementCreator, SqlProvider {
1348:
1349:                private final String callString;
1350:
1351:                public SimpleCallableStatementCreator(String callString) {
1352:                    Assert.notNull(callString, "Call string must not be null");
1353:                    this .callString = callString;
1354:                }
1355:
1356:                public CallableStatement createCallableStatement(Connection con)
1357:                        throws SQLException {
1358:                    return con.prepareCall(this .callString);
1359:                }
1360:
1361:                public String getSql() {
1362:                    return this .callString;
1363:                }
1364:
1365:            }
1366:
1367:            /**
1368:             * Adapter to enable use of a RowCallbackHandler inside a ResultSetExtractor.
1369:             * <p>Uses a regular ResultSet, so we have to be careful when using it:
1370:             * We don't use it for navigating since this could lead to unpredictable consequences.
1371:             */
1372:            private static class RowCallbackHandlerResultSetExtractor implements 
1373:                    ResultSetExtractor {
1374:
1375:                private final RowCallbackHandler rch;
1376:
1377:                public RowCallbackHandlerResultSetExtractor(
1378:                        RowCallbackHandler rch) {
1379:                    this .rch = rch;
1380:                }
1381:
1382:                public Object extractData(ResultSet rs) throws SQLException {
1383:                    while (rs.next()) {
1384:                        this.rch.processRow(rs);
1385:                    }
1386:                    return null;
1387:                }
1388:            }
1389:
1390:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.