Is there any tool or technique to identify opened ResultSet - java

In the context of a java application using SQLIte to persist data I am using the Zentus JDBC driver. Thus I am using the java.sql package to acces my database.
I am facing some strange (in a an environment with several Connection objects on the same database) issues and I am pretty sure my problems come from non closed ResultSet.
Is there any tool or technique allowing me to spot where to look in my source code to find these non closed objects ?
Edit May be using AspectJ ??

It seems like an aspect may be helpful.
How about wrapping the methods which return a result set in an aspect. Something like:
execution(public java.sql.ResultSet+ java.sql.Statement+.*(..))
Another aspect can monitor the close method on ResultSets. Perhaps:
execution(public * java.sql.ResultSet.close())
The first aspect would, on the return of every ResultSet, create a new Exception object and store it in a static Map somewhere using the hash of the ResultSet as the key. The second aspect, on the closing of the result set, would remove the Exception from the Map using the same hashcode as a key. At any time, the map should have one exception instance for every open ResultSet. From the exception you can obtain a stack trace to see where the ResultSet was opened.
You could perhaps store a larger object which includes an exception and some other contextual information; time that the ResultSet was created, etc.

A practical suggestion is to add some debug code and "log" creation and closing of resultsets to a csv file. Later on you could examine this file and check, if there's a "close" entry for each "create".
So, assuming you have a utility class with static methods that allows writing Strings to a file, you can do it like this:
ResultSet rs = stmt.executeQuery(query);
Util.writeln(rs.hashcode() + ";create"); // add this line whenever a
// new ResultSet is created
and
rs.close();
Util.writeln(rs.hashcode() + ";closed"); // add this line whenever a
// ResultSet is closed
Open the csv file with Excel or any other spread sheet program, sort the table and look if result sets are not closed. If this is the case, add more debug information to clearly identify the open sets.
BTW - Wrapping the interfaces (like JAMon) is pretty easy, if you have eclipse or something else, its coded in less then 15 Minutes. You'd need to wrap Connection, Statement (and PreparedStatement?) and ResultSet, the ResultSet wrapper could be instrumented to track and monitor creation and closing of result sets:
public MonitoredConnection implements Connection {
Connection wrappedConnection = null;
public MonitoredConnection(Connection wrappedConnection) {
this.wrappedConnection = wrappedConnection;
}
// ... implement interface methods and delegate to the wrappedConnection
#Override
public Statement createStatement() {
// we need MonitoredStatements because later we want MonitoredResultSets
return new MonitoredStatement(wrappedConnection.createStatemet());
}
// ...
}
The same for MonitoredStatement and MonitoredResultSet (MonitoredStatement will return wrapped ResultSets):
public MonitoredStatement implements Statement {
private Statement wrappedStatement = null;
#Override
public ResultSet executeQuery(String sql) throws SQLException
MonitoredResultSet rs = wrappedStatement.executeQuery(sql);
ResultSetMonitor.create(rs.getWrappedResultSet()); // some static utility class/method
return rs;
}
// ...
}
and
public MonitoredResultSet implements ResultSet {
private ResultSet wrappedResultSet;
#Override
public void close() {
wrappedResultSet.close();
ResultSetMonitor.close(wrappedResultSet); // some static utility class/method
}
// ...
}
At the end, you should only need to modify a single line in your code:
Connection con = DriverManager.getConnection(ur);
to
Connection con = new MonitoredConnection(DriverManager.getConnection(ur));

A Google Search pointed me directly to JAMon. It allows you to also monitor JDBC connections and cursors.
Personally, I would check the code and make sure that all Statement, PreparedStatement and ResultSet are closed when not needed. Even when using Connection Pooling, only JDBC Connection are returned into the pool and statements and ResultSet are closed.
This example shows how I achieve closing ResultSet and PreparedStatement in the finally close (for guarantee):
PreparedStatement ps = null;
ResultSet rs = null;
UserRequest request = null;
try {
ps = getConnection().prepareStatement(SQL_RETRIEVE);
ps.setLong(1, id);
rs = ps.executeQuery();
if (rs != null && rs.next()) {
request = mapEntity(rs);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
throw new DAOException(e);
} finally {
try {
close(rs, ps);
} catch (SQLException e) {
// TODO Auto-generated catch block
logger.error("Error closing statement or resultset.", e);
}
}
That's my 2 cents worth...hope it helps you.

It should be relatively simple to instrument your code with AOP of your choice. I was using AspectWerkz number of years ago to do load-time weaving of web app and collecting performance related statistics. Also if you're using IOC framework, such as Spring it's very easy to wrap your DataSources and trace calls to getConnection() etc.

Related

Unstable Oracle Database connection for Java-project

I'm a student and one of our assignments is creating a Java web project on a local GlassFish 5 webserver. The database used for this project is an OracleDB running locally in a Docker container.
I almost finished my project but some pages keep crashing (NullPointerException). I have to retrieve database records and save them in an ArrayList. But sometimes the SQLConnection doesn't return anything (but the records DO exist) and my code tries to preform actions on that empty ArrayList.
Now, as I said, the connection appears to be unstable, because at some seemingly random moments the database does respond with the appropriate records.
It's really frustrating and I cannot continue working on this project without a stable database connection. So I'd appreciate hearing from people with some more experience :-)
Thank you for your time.
Code for running a query:
protected ResultSet getRecords(String query) {
try {
Connection connection = DriverManager.getConnection(url, login, password);
Statement statement = connection.createStatement();
return (ResultSet) statement.executeQuery(query);
} catch (SQLException e) {
e.getStackTrace();
}
return null;
}
Code with the query:
List<Uitlening> uitleningen = new ArrayList<Uitlening>();
try {
ResultSet resultSet = getRecords("SELECT * FROM uitlening");
while(resultSet.next()) { //Here the code crashes because the ResultSet can sometimes be empty.
I think this is the actual error message: Listener refused the connection with the following error: ORA-12519, TNS:no appropriate service handler found
But I don't really understand what I should do now..
try {
ResultSet resultSet = getRecords("SELECT * FROM uitlening");
while(resultSet.next()) {
Uitlening uitlening = new Uitlening();
uitlening.setNr(resultSet.getInt("nr"));
uitleningen.add(uitlening);
}
} catch (SQLException e) {
e.addSuppressed(e);
}
return uitleningen;
It might be nothing, but it almost looks like the error only occurs when I run 2 queries almost immediately after each other. Is it possible that closing the connection takes a while?
Chances are that you run into the database connection problem because your code does not properly close the database connections as well as the statements and result sets.
A statement will also close its active result set. Most JDBC will also close the statement if the connection is closed.
So closing the connection is the most important part. It cannot be achieved with your current code structure because you create it in an inner method and do not return it.
It has also been mentioned that the exception handling is poor because you ignore exceptions and return null instead causing seemingly unrelated crashes later. In many cases it might be easier to declare that the method throws SQLException.
You might want to change your code like so:
List<Uitlening> retrieveData() {
final String query = "SELECT * FROM uitlening";
try (Connection connection = DriverManager.getConnection(url, login, password);
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query)) {
return processResultSet(resultSet);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
List<Uitlening> processResultSet(ResultSet resultSet) throws SQLException {
List<Uitlening> uitleningen = new ArrayList<>();
while (resultSet.next()) {
Uitlening uitlening = new Uitlening();
uitlening.setNr(resultSet.getInt("nr"));
uitleningen.add(uitlening);
}
return uitleningen;
}
It closes the connection, the statement and the result set by using try/catch blocks that take advantage of AutoClosables (in this case: Connection, Statement, ResultSet).
The method processResultSet declares the SQLException so it doesn't need to handle it.
The code is rearrange so the data is fully processed before the code leaves the try/catch block that closes the connection.

Try / Try-with-resources and Connection, Statement and ResultSet closing

I have recently having some discussions with my professor about how to handle the basic jdbc connection scheme. Suppose we want to execute two queries, this is what he proposes
public void doQueries() throws MyException{
Connection con = null;
try {
con = DriverManager.getConnection(dataSource);
PreparedStatement s1 = con.prepareStatement(updateSqlQuery);
PreparedStatement s2 = con.prepareStatement(selectSqlQuery);
// Set the parameters of the PreparedStatements and maybe do other things
s1.executeUpdate();
ResultSet rs = s2.executeQuery();
rs.close();
s2.close();
s1.close();
} catch (SQLException e) {
throw new MyException(e);
} finally {
try {
if (con != null) {
con.close();
}
} catch (SQLException e2) {
// Can't really do anything
}
}
}
I don't like this approach, and I have two questions about it:
1.A) I think that, if any exception is thrown where we do 'other things', or in the line rs.close() or s2.close() then s1 wouldn't have been closed when the method ends. Am I right about that?
1.B) The professor keeps asking me to explicitly close the ResultSet (even when the Statement documentation makes clear that it will close the ResultSet) She says that Sun recommends it. Is there any reason to do so?
Now this is what I think is the correct code for the same thing:
public void doQueries() throws MyException{
Connection con = null;
PreparedStatement s1 = null;
PreparedStatement s2 = null;
try {
con = DriverManager.getConnection(dataSource);
s1 = con.prepareStatement(updateSqlQuery);
s2 = con.prepareStatement(selectSqlQuery);
// Set the parameters of the PreparedStatements and maybe do other things
s1.executeUpdate();
ResultSet rs = s2.executeQuery();
} catch (SQLException e) {
throw new MyException(e);
} finally {
try {
if (s2 != null) {
s2.close();
}
} catch (SQLException e3) {
// Can't do nothing
}
try {
if (s1 != null) {
s1.close();
}
} catch (SQLException e3) {
// Can't do nothing
}
try {
if (con != null) {
con.close();
}
} catch (SQLException e2) {
// Can't do nothing
}
}
}
2.A) Is this code correct? (Is it guaranteed that all will be closed when the method ends?)
2.B) This is very large and verbose (and it gets worse if there are more Statements) Is there any shorter or more elegant way to do this without using try-with-resources?
Finally this is the code I like the most
public void doQueries() throws MyException{
try (Connection con = DriverManager.getConnection(dataSource);
PreparedStatement s1 = con.prepareStatement(updateSqlQuery);
PreparedStatement s2 = con.prepareStatement(selectSqlQuery))
{
// Set the parameters of the PreparedStatements and maybe do other things
s1.executeUpdate();
ResultSet rs = s2.executeQuery();
} catch (SQLException e) {
throw new MyException(e);
}
}
3) Is this code correct? I think my professor doesn't like this way because there is no explicit close of the ResultSet, but she has told me that she is fine with it as long as in the documentation it is clear that all is closed. Can you give any link to the official documentation with a similar example, or based in the documentation show that there is are no problems with this code?
tl;dr
In theory closing the statement closes the result set.
In practice, some faulty JDBC driver implementations failed to do so, notoriously. Thus the advice from your instructor that she learned from the School Of Hard Knocks.
Unless you are familiar with every implementation of every JDBC
driver that might be deployed for your app, use
try-with-resources to auto-close every level of your JDBC
work such as statements and result sets.
Use try-with-resources syntax
None of your code is fully using try-with-resources. In try-with-resources syntax, you declare and instantiate your Connection, PreparedStatement, and ResultSet in parentheses, before the braces. See Tutorial by Oracle.
While your ResultSet is not being explicitly closed in your last code example, it should be closed indirectly when its statement is closed. But as discussed below, it might not be closed because of faulty JDBC driver.
AutoCloseable
Any such objects implementing AutoCloseable will automatically have their close method invoked. So no need for those finally clauses.
How do you know which objects are auto-closable and which are not? Look at their class documentation to see if it declares AutoCloseable as a super-interface. Conversely, see the JavaDoc page for AutoCloseable for a list of all the bundled sub-interfaces and implementing classes (dozens actually).
For example, for SQL work, we see that Connection, Statement, PreparedStatement, ResultSet, and RowSet are all auto-closable but DataSource is not. This makes sense, as DataSource stores data about potential resources (database connections) but is not itself a resource. A DataSource is never “open” so no need to close.
See Oracle Tutorial, The try-with-resources Statement.
Code example
Your last code example is getting close to good, but should have wrapped ResultSet in a try-with-resources statement to get automatically closed.
To quote ResultSet JavaDoc:
A ResultSet object is automatically closed when the Statement object that generated it is closed, re-executed, or used to retrieve the next result from a sequence of multiple results.
As your teacher has been suggesting, there have been serious flaws in some JDBC drivers that failed to live up to the promise of the JDBC spec to close the ResultSet when its Statement or PreparedStatement is closed. So many programmers make a habit of closing each ResultSet object explicitly.
This extra duty is easier now with the try-with-resources syntax. In real work you’ll likely have a try-else around all your AutoCloseable objects such as ResultSet anyways. So my own opinion is: Why not make it a try-with-resources + else? Does not hurt, makes your code more self-documenting about your intentions, and it might help if your code ever encounters one of those faulty JDBC drivers. The only cost is a pair of parens, assuming you’d have a try-catch-else in place anyways.
As stated in the Oracle Tutorial, multiple AutoCloseable objects declared together will be closed in reverse order, just as we would want.
Tip: The try-with-resources syntax allows an optional semicolon on the last declared resource item. I include the semicolon as a habit because it reads well to my eye, is consistent, and facilitates cut-and-paste editing. I include it on your PreparedStatement s2 line.
public void doQueries() throws MyException{
// First try-with-resources.
try ( Connection con = DriverManager.getConnection( dataSource ) ;
PreparedStatement s1 = con.prepareStatement( updateSqlQuery ) ;
PreparedStatement s2 = con.prepareStatement( selectSqlQuery ) ;
) {
… Set parameters of PreparedStatements, etc.
s1.executeUpdate() ;
// Second try-with-resources, nested within first.
try (
ResultSet rs = s2.executeQuery() ;
) {
… process ResultSet
} catch ( SQLException e2 ) {
… handle exception related to ResultSet.
}
} catch ( SQLException e ) {
… handle exception related to Connection or PreparedStatements.
}
}
I suppose there is a more elegant syntax for this kind of work that might be invented in a future programming language. But for now, we have try-with-resources, and I do use it happily. While try-with-resources is not perfectly elegant, it is a big improvement over the older syntax.
By the way, Oracle recommends using a DataSource implementation for getting connections rather than the DriverManager approach seen in your code. Using DataSource throughout your code makes it easier to switch drivers or switch to a connection pool. See if your JDBC driver provides an implementation of DataSource.
Update: Java 9
Now in Java 9 you can initialize the resources before the try-with-resources. See this article. This flexibility may be useful in some scenarios.
The fun thing about JDBC code is that you're coding to a spec where it's not always clear how compliant your implementation is. There are a lot of different databases and drivers and some drivers are better-behaved than others. That tends to make people err on the side of caution, recommending things like closing everything explicitly. You could be ok with closing only the connection here. Closing the resultSet just to be on the safe side is hard to argue with. You don't indicate what database or driver you're using here, i wouldn't want to hardcode in assumptions about the driver that might not be valid for some implementation.
Closing things in sequence does leave you open to problems where an exception can get thrown and cause some of the closes to be skipped. You're right to be concerned about that.
Be aware this is a toy example. Most real code uses a connection pool, where calling the close method doesn't actually close the connection, instead it returns the connection to the pool. So resources may not get closed once you use a pool. If you want to change this code to use a connection pool then you'll have to go back and close the statements at least.
Also if you're objecting to the verbosity of this, the answer to that is to hide the code in reusable utilities that use strategies, resultSet mappers, prepared statement setters, etc. This has all been done before, of course; you'll be on the road to reinventing Spring JDBC.
Speaking of which: Spring JDBC closes everything explicitly (probably because it needs to work with as many drivers as possible, and doesn't want to cause problems due to some driver's not being well-behaved).
This is what I find to be the best solution for handling resources like JDBC. This method provides an immutable function, by leveraging final variables, and only declaring and assigning those variables if they are needed, it is very CPU efficient, and guarantees in all cases, that all resources that are assigned and opened are closed regardless of the state of exceptions. The technique you are using leaves gaps that can result in resource leaks if not carefully implemented to address all scenarios. This technique does not allow for a resource leak provided the pattern is always followed:
1) assign resource
2) try
3) use resource
4) finally close resource
public void doQueries() throws MyException {
try {
final Connection con = DriverManager.getConnection(dataSource);
try {
final PreparedStatement s1 = con.prepareStatement(updateSqlQuery);
try {
// Set the parameters of the PreparedStatements and maybe do other things
s1.executeUpdate();
} finally {
try { s1.close(); } catch (SQLException e) {}
}
final PreparedStatement s2 = con.prepareStatement(selectSqlQuery);
try {
// Set the parameters of the PreparedStatements and maybe do other things
final ResultSet rs = s2.executeQuery();
try {
// Do something with rs
} finally {
try { rs.close(); } catch (SQLException e) {}
}
} finally {
try { s2.close(); } catch (SQLException e) {}
}
} finally {
try { con.close(); } catch (SQLException e) {}
}
} catch (SQLException e) {
throw new MyException(e);
}
}
With Java 7, you can leverage the new try -with-resources to simplify this even more: The new try -with-resources follows the above logic flow, in that it will guarantee all resources include in the with resources block that are assigned get closed. any exception thrown in the with resources block will the thrown, but those assigned resources will still be closed. This code is much simplified and looks like this:
public void doQueries() throws MyException {
try (
final Connection con = DriverManager.getConnection(dataSource);
final PreparedStatement s1 = con.prepareStatement(updateSqlQuery);
final PreparedStatement s2 = con.prepareStatement(selectSqlQuery);
final ResultSet rs = s2.executeQuery()) {
s1.executeUpdate();
// Do something with rs
} catch (SQLException e) {
throw new MyException(e);
}
}
[EDIT]: moved rs assignment into the resources block to show the simplest implementation. In practice, this simple solution does not really work, as this is not efficient. A connection should be reused, since establishing the connection is a very costly operation. Additionally, this simple example does not assign query parameters to the prepared statement. Care should be taken to handle these scenarios, as the the resource block should only include assignment statements. To depict this, I have also added another example
public void doQueries() throws MyException {
final String updateSqlQuery = "select ##servername";
final String selecSqlQuery = "select * from mytable where col1 = ? and col2 > ?";
final Object[] queryParams = {"somevalue", 1};
try (final Connection con = DriverManager.getConnection(dataSource);
final PreparedStatement s1 = newPreparedStatement(con, updateSqlQuery);
final PreparedStatement s2 = newPreparedStatement(con, selectSqlQuery, queryParams);
final ResultSet rs = s2.executeQuery()) {
s1.executeUpdate();
while (!rs.next()) {
// do something with the db record.
}
} catch (SQLException e) {
throw new MyException(e);
}
}
private static PreparedStatement newPreparedStatement(Connection con, String sql, Object... args) throws SQLException
{
final PreparedStatement stmt = con.prepareStatement(sql);
for (int i = 0; i < args.length; i++)
stmt.setObject(i, args[i]);
return stmt;
}
This is indeed the primary motivation for try-with-resources. See the Java tutorials as reference. Your professor is out-of-date. If you want to deal with the result set issue you can always enclose it in another try-with-resources statement.
You could make a util class to handle closing of these resources. i.e
FYI i just ignored SQLExceptions from trying to close resources in the util class, but you could as verywell log or collect and throw them once you are done closing the resources in the collection depending on your needs
public class DBUtil {
public static void closeConnections(Connection ...connections){
if(connections != null ){
for(Connection conn : connections){
if(conn != null){
try {
conn.close();
} catch (SQLException ignored) {
//ignored
}
}
}
}
}
public static void closeResultSets(ResultSet ...resultSets){
if(resultSets != null ){
for(ResultSet rs: resultSets){
if(rs != null){
try {
rs.close();
} catch (SQLException ignored) {
//ignored
}
}
}
}
}
public static void closeStatements(Statement ...statements){
if(statements != null){
for(Statement statement : statements){
if(statement != null){
try {
statement.close();
} catch (SQLException ignored) {
//ignored
}
}
}
}
}
}
and then just call it from you method:
public void doQueries() throws MyException {
Connection con = null;
try {
con = DriverManager.getConnection(dataSource);
PreparedStatement s1 = null;
PreparedStatement s2 = null;
try {
s1 = con.prepareStatement(updateSqlQuery);
s2 = con.prepareStatement(selectSqlQuery);
// Set the parameters of the PreparedStatements and maybe do other things
s1.executeUpdate();
ResultSet rs = null;
try {
rs = s2.executeQuery();
} finally {
DBUtil.closeResultSets(rs);
}
} finally {
DBUtil.closeStatements(s2, s1);
}
} catch (SQLException e) {
throw new MyException(e);
} finally {
DBUtil.closeConnections(con);
}
}
I prefer to let Java auto-close. So I do something like this when I have to set values for ResultSet.
try (Connection conn = DB.getConn();
PreparedStatement ps = conn.prepareStatement("SELECT * FROM x WHERE y = ?")
) {
ps.setString(1, "yValue");
try(ResultSet rs = ps.executeQuery()) {
while(rs.next()) {
...
}
}
} catch (SQLException e) {
e.printStackTrace(e);
...
}

Java Create statement usage in while loop

Which of the following is correct (or does it matter).
Connection conn = null;
conn = DriverManager.getConnection (url, userName, password);
Statement st = conn.createStatement();
while (a.b()) {
st.executeUpdate(blah blah); // same statement with different data values
}
st.close();
conn.close();
finally
{
if (conn != null)
{
try
{
conn.close ();
}
catch (Exception e) { }
}
}
}
or
Connection conn = null;
conn = DriverManager.getConnection (url, userName, password);
while (a.b()) {
Statement st = conn.createStatement();
st.executeUpdate(blah blah); //same statement with different data values
st.close();
}
conn.close();
finally
{
if (conn != null)
{
try
{
conn.close ();
}
catch (Exception e) { }
}
}
}
Creating the statement outside the loop is cleaner, and may be somewhat faster, though you'd need to profile in order to see if it makes much difference in your case.
If the loop is doing the same thing with different data values, I would prefer PreparedStatement for speed.
If the update inside the loop reuses the exact same statement, then the first form is preferred. On the contrary, if the statement changes with each iteration, then you're stuck with the second form.
Really, you should be using PreparedStatement with placeholders and only creating the statement once as in your first example.
I don't think there's a big difference in the above case - you would like to close the statement if there's enough work in between for it to stay open for a long time - as per the docs:
http://docs.oracle.com/javase/6/docs/api/java/sql/Statement.html#close()
Releases this Statement object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed. It is generally good practice to release resources as soon as you are finished with them to avoid tying up database resources.
Unless your SQL changes, the best is to use PreparedStatement instead, using the first way you specified.
Neither is correct. Assuming that you are not repeatedly executing the exact same query, but that they have different values, then you should be using a (single) PreparedStatement with a query that has placeholders and supplying the different values at each loop iteration.
Using a prepared statement will be more efficient on the Java side (by reducing object creation and GC costs). It could also reduce the load on the database side depending on how the JDBC drivers work.
The other point is that you need to close the PreparedStatement and the Connection in the finally clause of a try. If you don't and an exception is thrown, then your code will leak a database connection. This could cause problems later on.

Why is this query not returning any results?

I am leaning some Java for school, and for some reason the code below doesn't return any results? Is there a problem with this code? There is a single record in the mysql database, with a studentID (which is int(10)) of 12.
public static ResultSet GetByID(int studentID) {
// This method loads the mysql driver and establishes the database connection
Connect();
ResultSet results = null;
try {
String query = "SELECT * FROM student where studentID = ?";
PreparedStatement statement = Connection.prepareStatement(query);
statement.setInt(1, studentID);
results = statement.executeQuery();
} catch (SQLException ex) {
LogException(ex);
} catch (Exception ex) {
System.out.println(ex);
}
// This method terminates the mysql connection.
Disconnect();
return results;
}
The calling code is:
#Override
public ResultSet query() {
return DB.GetByID(getStudentID()); // this is 12
}
This does not return null, rather just an empty result set.
A ResultSet can only be used while the connection is still open. Read it before you "disconnect".
If fixing that doesn't give you a different result, the most likely cause is that the query didn't match any rows in the table.
You should get into the habit of closing connections, streams, etc in finally blocks to prevent resource leakage. (Your lecturer should have explained that. Check your notes / text book.)
Finally, since you are a beginner, it is worth pointing out that you should always conform to the accepted Java conventions for method naming. Java method names should start with a lower-case letter. GetByID should be getByID and Disconnect should be disconnect.
(And if your lecturer / tutor doesn't or didn't dock marks for that, he / she should be condemned to writing Visual Basic for the next 5 years for crimes against the Software Engineering industry.)
If you want to return the resultSet after closing the connection you have to use CachedRowSet.
As StephenC said, your ResultSet is empty after closing the connection.

Why do I need a connection to create PreparedStatements?

I would like to use prepared statements, for many reasons.
But, I would like to create a method that looks like this:
/* This opens a connection, executes the query, and closes the connection */
public static void executeNonQuery(String queryString);
In other words, I want my application logic to only have to formulate the queries and feed in parameters, but not deal with connections & statements. However, PreparedStatements are created from a connection object, so I am currently forced into preparing the query string using String.format() - butt ugly and dangerous.
Is there a way to do what I want without using String.format()?
Why do I need a connection to create PreparedStatements ?
Because the statements are prepared on per-connection basis in most RDBMS's.
Prepared statements are in fact cached execution plans that don't take you permissions, encodings, collation settings etc. into account.
All this is done during query parsing.
Is there a way to do what I want without using String.format()
Don't see why you need String.format() here.
You can implement your query as a class, create a connection and prepare the query in the class constructor and then execute it in a method.
A parametrized query typically looks like this:
SELECT *
FROM table
WHERE col1 = ?
AND col2 = ?
, where the bound parameters will be substituted for ?'s during the query execution.
If you want a static method:
Create a static connection handle.
Create a static hash table of prepared queries using the parametrized query text as a key, and the handle to the prepared query as a value.
Whenever you want to execute a query, find its handle (or create it if it wasn't found) and use to to bind the parameters and execute the query.
Why not have your "application" logic use a data layer which you create which can present that kind of interface method?
Your data layer can then handle creating connections, preparing statements, etc., all within that executeNonQuery method.
I think that if you are attempting to merge the parameters in your query/statement yourself into a String, then you are shooting yourself in the foot and actually not using the parameter functionality of PreparedStatements. Not sure why you would want to do this.
You might also want to look into using an API such as Spring, which has a series of JdbcTemplate classes that can abstract all of the connection handling away from you, but still allow you to work with parameters in a Map.
You probably want something like the DbUtils package in the Apache Commons libraries: [http://commons.apache.org/dbutils/index.html][1]
The QueryRunner class lets you execute sql statements without having to manually create PreparedStatements, or even have an open connection for that matter. From the examples page:
QueryRunner run = new QueryRunner( dataSource );
try
{
// Create an object array to hold the values to insert
Object[] insertParams = {"John Doe", new Double( 1.82 )};
// Execute the SQL update statement and return the number of
// inserts that were made
int inserts = run.update( "INSERT INTO Person (name,height) VALUES (?,?)",
insertParams );
// Now it's time to rise to the occation...
Object[] updateParams = {new Double( 2.05 ), "John Doe"};
int updates = run.update( "UPDATE Person SET height=? WHERE name=?",
updateParams );
}
catch(SQLException sqle) {
// Handle it
}
So it basically handles the creation of prepared statements transparently, and the only thing you really need to know is a DataSource. This also works just as well for non-update/insert statements, i.e. plain-vanilla select queries, and the ability to create ResultSetHandlers gives you the power to convert a ResultSet into something like a fully-prepared bean, or a Map with the keys being the column names, and the values being the actual row values. Very useful for when you can't implement a whole ORM solution.
I abstract out all of the JDBC stuff by having a class I call QueryRunner that has an execute method that takes the sql, a List of objects that represent the parameters, and an object that will process the ResultSet. If you use the setObject method from JDBC to set your parameters it will figure out the appropriate DB types to use based on the underlying object. Here is a portion of my code. I've got another method that wraps this one and get's the connection.
public void executeNoCommit(Connection conn,
String sql,
List params,
ResultSetProcessor processor) throws SQLException {
PreparedStatement stmt = null;
ResultSet rs = null;
int updateCount = 0;
Iterator it;
int paramIndex = 1;
boolean query;
try {
stmt = conn.prepareStatement(sql);
if (params != null) {
it = params.iterator();
while (it.hasNext()) {
stmt.setObject(paramIndex, it.next());
paramIndex++;
}
}
query = stmt.execute();
if (query) {
rs = stmt.getResultSet();
}
else {
updateCount = stmt.getUpdateCount();
}
processor.process(rs, updateCount);
}
finally {
if (rs != null) {
try {
rs.close();
}
catch (SQLException e) {
log.error(e);
}
}
if (stmt != null) {
try {
stmt.close();
}
catch (SQLException e) {
log.error(e);
}
}
}
}

Categories