Skip to content

Commit a7d4377

Browse files
committed
Merge pull request spring-projects#90 from ianbrandt/SPR-9235
* SPR-9235: Deprecate SimpleJdbcTestUtils in favor of JdbcTestUtils
2 parents 04bfc80 + bd0c4b4 commit a7d4377

File tree

3 files changed

+229
-19
lines changed

3 files changed

+229
-19
lines changed

spring-test/src/main/java/org/springframework/test/jdbc/JdbcTestUtils.java

Lines changed: 224 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2009 the original author or authors.
2+
* Copyright 2002-2012 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,27 +18,232 @@
1818

1919
import java.io.IOException;
2020
import java.io.LineNumberReader;
21+
import java.util.LinkedList;
2122
import java.util.List;
2223

24+
import org.apache.commons.logging.Log;
25+
import org.apache.commons.logging.LogFactory;
26+
27+
import org.springframework.core.io.Resource;
28+
import org.springframework.core.io.ResourceLoader;
29+
import org.springframework.core.io.support.EncodedResource;
30+
import org.springframework.dao.DataAccessException;
31+
import org.springframework.dao.DataAccessResourceFailureException;
32+
import org.springframework.jdbc.core.JdbcTemplate;
2333
import org.springframework.util.StringUtils;
2434

2535
/**
26-
* JdbcTestUtils is a collection of JDBC related utility methods for use in unit
27-
* and integration testing scenarios.
36+
* {@code JdbcTestUtils} is a collection of JDBC related utility functions
37+
* intended to simplify standard database testing scenarios.
2838
*
39+
* <p>As of Spring 3.2, {@code JdbcTestUtils} supersedes {@link SimpleJdbcTestUtils}.
40+
*
2941
* @author Thomas Risberg
42+
* @author Sam Brannen
43+
* @author Juergen Hoeller
3044
* @since 2.5.4
3145
*/
3246
public class JdbcTestUtils {
3347

48+
private static final Log logger = LogFactory.getLog(JdbcTestUtils.class);
49+
50+
51+
/**
52+
* Count the rows in the given table.
53+
*
54+
* @param jdbcTemplate the JdbcTemplate with which to perform JDBC operations
55+
* @param tableName name of the table to count rows in
56+
* @return the number of rows in the table
57+
* @since 3.2
58+
*/
59+
public static int countRowsInTable(JdbcTemplate jdbcTemplate, String tableName) {
60+
return jdbcTemplate.queryForInt("SELECT COUNT(0) FROM " + tableName);
61+
}
62+
63+
/**
64+
* Count the rows in the given table, using the provided {@code WHERE} clause.
65+
*
66+
* <p>If the provided {@code WHERE} clause contains text, it will be prefixed
67+
* with {@code " WHERE "} and then appended to the generated {@code SELECT}
68+
* statement. For example, if the provided table name is {@code "person"} and
69+
* the provided where clause is {@code "name = 'Bob' and age > 25"}, the
70+
* resulting SQL statement to execute will be
71+
* {@code "SELECT COUNT(0) FROM person WHERE name = 'Bob' and age > 25"}.
72+
*
73+
* @param jdbcTemplate the JdbcTemplate with which to perform JDBC operations
74+
* @param tableName the name of the table to count rows in
75+
* @param whereClause the {@code WHERE} clause to append to the query
76+
* @return the number of rows in the table that match the provided
77+
* {@code WHERE} clause
78+
* @since 3.2
79+
*/
80+
public static int countRowsInTableWhere(JdbcTemplate jdbcTemplate, String tableName, String whereClause) {
81+
String sql = "SELECT COUNT(0) FROM " + tableName;
82+
83+
if (StringUtils.hasText(whereClause)) {
84+
sql += " WHERE " + whereClause;
85+
}
86+
87+
return jdbcTemplate.queryForInt(sql);
88+
}
89+
90+
/**
91+
* Delete all rows from the specified tables.
92+
*
93+
* @param jdbcTemplate the JdbcTemplate with which to perform JDBC operations
94+
* @param tableNames the names of the tables to delete from
95+
* @return the total number of rows deleted from all specified tables
96+
* @since 3.2
97+
*/
98+
public static int deleteFromTables(JdbcTemplate jdbcTemplate, String... tableNames) {
99+
int totalRowCount = 0;
100+
for (String tableName : tableNames) {
101+
int rowCount = jdbcTemplate.update("DELETE FROM " + tableName);
102+
totalRowCount += rowCount;
103+
if (logger.isInfoEnabled()) {
104+
logger.info("Deleted " + rowCount + " rows from table " + tableName);
105+
}
106+
}
107+
return totalRowCount;
108+
}
109+
110+
/**
111+
* Drop the specified tables.
112+
*
113+
* @param jdbcTemplate the JdbcTemplate with which to perform JDBC operations
114+
* @param tableNames the names of the tables to drop
115+
* @since 3.2
116+
*/
117+
public static void dropTables(JdbcTemplate jdbcTemplate, String... tableNames) {
118+
for (String tableName : tableNames) {
119+
jdbcTemplate.execute("DROP TABLE " + tableName);
120+
if (logger.isInfoEnabled()) {
121+
logger.info("Dropped table " + tableName);
122+
}
123+
}
124+
}
125+
34126
/**
35-
* Read a script from the LineNumberReader and build a String containing the
36-
* lines.
37-
*
38-
* @param lineNumberReader the <code>LineNumberReader</code> containing the
39-
* script to be processed
40-
* @return <code>String</code> containing the script lines
41-
* @throws IOException
127+
* Execute the given SQL script.
128+
*
129+
* <p>The script will typically be loaded from the classpath. There should
130+
* be one statement per line. Any semicolons will be removed.
131+
*
132+
* <p><b>Do not use this method to execute DDL if you expect rollback.</b>
133+
*
134+
* @param jdbcTemplate the JdbcTemplate with which to perform JDBC operations
135+
* @param resourceLoader the resource loader with which to load the SQL script
136+
* @param sqlResourcePath the Spring resource path for the SQL script
137+
* @param continueOnError whether or not to continue without throwing an
138+
* exception in the event of an error
139+
* @throws DataAccessException if there is an error executing a statement
140+
* and {@code continueOnError} is {@code false}
141+
* @since 3.2
142+
*/
143+
public static void executeSqlScript(JdbcTemplate jdbcTemplate, ResourceLoader resourceLoader,
144+
String sqlResourcePath, boolean continueOnError) throws DataAccessException {
145+
Resource resource = resourceLoader.getResource(sqlResourcePath);
146+
executeSqlScript(jdbcTemplate, resource, continueOnError);
147+
}
148+
149+
/**
150+
* Execute the given SQL script.
151+
*
152+
* <p>The script will typically be loaded from the classpath. Statements
153+
* should be delimited with a semicolon. If statements are not delimited with
154+
* a semicolon then there should be one statement per line. Statements are
155+
* allowed to span lines only if they are delimited with a semicolon.
156+
*
157+
* <p><b>Do not use this method to execute DDL if you expect rollback.</b>
158+
*
159+
* @param jdbcTemplate the JdbcTemplate with which to perform JDBC operations
160+
* @param resource the resource to load the SQL script from
161+
* @param continueOnError whether or not to continue without throwing an
162+
* exception in the event of an error
163+
* @throws DataAccessException if there is an error executing a statement
164+
* and {@code continueOnError} is {@code false}
165+
* @since 3.2
166+
*/
167+
public static void executeSqlScript(JdbcTemplate jdbcTemplate, Resource resource, boolean continueOnError)
168+
throws DataAccessException {
169+
executeSqlScript(jdbcTemplate, new EncodedResource(resource), continueOnError);
170+
}
171+
172+
/**
173+
* Execute the given SQL script.
174+
*
175+
* <p>The script will typically be loaded from the classpath. There should
176+
* be one statement per line. Any semicolons will be removed.
177+
*
178+
* <p><b>Do not use this method to execute DDL if you expect rollback.</b>
179+
*
180+
* @param jdbcTemplate the JdbcTemplate with which to perform JDBC operations
181+
* @param resource the resource (potentially associated with a specific encoding)
182+
* to load the SQL script from
183+
* @param continueOnError whether or not to continue without throwing an
184+
* exception in the event of an error
185+
* @throws DataAccessException if there is an error executing a statement
186+
* and {@code continueOnError} is {@code false}
187+
* @since 3.2
188+
*/
189+
public static void executeSqlScript(JdbcTemplate jdbcTemplate, EncodedResource resource, boolean continueOnError)
190+
throws DataAccessException {
191+
192+
if (logger.isInfoEnabled()) {
193+
logger.info("Executing SQL script from " + resource);
194+
}
195+
196+
long startTime = System.currentTimeMillis();
197+
List<String> statements = new LinkedList<String>();
198+
LineNumberReader reader = null;
199+
try {
200+
reader = new LineNumberReader(resource.getReader());
201+
String script = readScript(reader);
202+
char delimiter = ';';
203+
if (!containsSqlScriptDelimiters(script, delimiter)) {
204+
delimiter = '\n';
205+
}
206+
splitSqlScript(script, delimiter, statements);
207+
for (String statement : statements) {
208+
try {
209+
int rowsAffected = jdbcTemplate.update(statement);
210+
if (logger.isDebugEnabled()) {
211+
logger.debug(rowsAffected + " rows affected by SQL: " + statement);
212+
}
213+
} catch (DataAccessException ex) {
214+
if (continueOnError) {
215+
if (logger.isWarnEnabled()) {
216+
logger.warn("SQL statement [" + statement + "] failed", ex);
217+
}
218+
} else {
219+
throw ex;
220+
}
221+
}
222+
}
223+
long elapsedTime = System.currentTimeMillis() - startTime;
224+
if (logger.isInfoEnabled()) {
225+
logger.info(String.format("Executed SQL script from %s in %s ms.", resource, elapsedTime));
226+
}
227+
} catch (IOException ex) {
228+
throw new DataAccessResourceFailureException("Failed to open SQL script from " + resource, ex);
229+
} finally {
230+
try {
231+
if (reader != null) {
232+
reader.close();
233+
}
234+
} catch (IOException ex) {
235+
// ignore
236+
}
237+
}
238+
}
239+
240+
/**
241+
* Read a script from the provided {@code LineNumberReader} and build a
242+
* {@code String} containing the lines.
243+
*
244+
* @param lineNumberReader the {@code LineNumberReader} containing the script
245+
* to be processed
246+
* @return a {@code String} containing the script lines
42247
*/
43248
public static String readScript(LineNumberReader lineNumberReader) throws IOException {
44249
String currentStatement = lineNumberReader.readLine();
@@ -56,11 +261,13 @@ public static String readScript(LineNumberReader lineNumberReader) throws IOExce
56261
}
57262

58263
/**
59-
* Does the provided SQL script contain the specified delimiter?
60-
*
264+
* Determine if the provided SQL script contains the specified delimiter.
265+
*
61266
* @param script the SQL script
62-
* @param delim character delimiting each statement - typically a ';'
267+
* @param delim character delimiting each statement &mdash; typically a ';'
63268
* character
269+
* @return {@code true} if the script contains the delimiter; {@code false}
270+
* otherwise
64271
*/
65272
public static boolean containsSqlScriptDelimiters(String script, char delim) {
66273
boolean inLiteral = false;
@@ -80,11 +287,11 @@ public static boolean containsSqlScriptDelimiters(String script, char delim) {
80287
* Split an SQL script into separate statements delimited with the provided
81288
* delimiter character. Each individual statement will be added to the
82289
* provided <code>List</code>.
83-
*
290+
*
84291
* @param script the SQL script
85-
* @param delim character delimiting each statement - typically a ';'
292+
* @param delim character delimiting each statement &mdash; typically a ';'
86293
* character
87-
* @param statements the List that will contain the individual statements
294+
* @param statements the list that will contain the individual statements
88295
*/
89296
public static void splitSqlScript(String script, char delim, List<String> statements) {
90297
StringBuilder sb = new StringBuilder();
@@ -99,8 +306,7 @@ public static void splitSqlScript(String script, char delim, List<String> statem
99306
statements.add(sb.toString());
100307
sb = new StringBuilder();
101308
}
102-
}
103-
else {
309+
} else {
104310
sb.append(content[i]);
105311
}
106312
}

spring-test/src/main/java/org/springframework/test/jdbc/SimpleJdbcTestUtils.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.io.IOException;
2020
import java.io.LineNumberReader;
21+
2122
import java.util.LinkedList;
2223
import java.util.List;
2324

@@ -39,8 +40,9 @@
3940
* @author Juergen Hoeller
4041
* @author Thomas Risberg
4142
* @since 2.5
43+
* @deprecated As of Spring 3.2, use {@link JdbcTestUtils} instead.
4244
*/
43-
@SuppressWarnings("deprecation")
45+
@Deprecated
4446
public abstract class SimpleJdbcTestUtils {
4547

4648
private static final Log logger = LogFactory.getLog(SimpleJdbcTestUtils.class);

src/dist/changelog.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ Changes in version 3.2 M2 (2012-08-xx)
3030
* introduced support for single, unqualified tx manager in the TestContext framework (SPR-9645)
3131
* introduced support for TransactionManagementConfigurer in the TestContext framework (SPR-9604)
3232
* introduced MockEnvironment in the spring-test module (SPR-9492)
33+
* deprecated SimpleJdbcTestUtils in favor of JdbcTestUtils (SPR-9235)
34+
* introduced countRowsInTableWhere() and dropTables() in JdbcTestUtils (SPR-9235)
3335

3436

3537
Changes in version 3.2 M1 (2012-05-28)

0 commit comments

Comments
 (0)