tags:

views:

89

answers:

4

I'm pretty new to JDBC, so this is probably a very straightforward question.

I have to run several SQL statements, so I'm trying to write a generic "runSQLResultSet" method that takes a String sql statement and returns a ResultSet. I want it to take care of opening the database connection, executing the statement, storing the ResultSet in a CachedRowSetImpl object (so that it will persist after the connection is closed), and closing the connection. I created a method that does this and it works.

My problem now is that I want to be able to use it for dynamic statements that are built with variables. I looked around, and it seems that I should really change my method to take a PreparedStatement instead of just a plain String. Then I can build the PreparedStatement on the other side and pass it to the method. The problem is that I can't seem to create a PreparedStatement without a Connection object. I can open the connection before preparing the statement, but that defeats my purpose of factoring out the database processing into the runSQLResultSet method. I need a way to build a SQL statement with dynamic components, without a connection object, and pass it to a method that will then execute it. Is there any way to do this with a PreparedStatement? Is there any other statement object I can use instead? Otherwise - is there any better way to do this?

A: 

what you are missing is the concept of Database connection pooling, you should never be instantiaing connections directly, the pool controls the database connections under the covers. You can look at my open source project SQL Construction Kit for some inspiration on one light weight way to deal with JDBC and how to build dynamic SQL statements using Factory and Builder patterns.

fuzzy lollipop
+1  A: 

You cannot create one without a DB connection. A PreparedStatement will be precompiled in the DB and thus really needs an open connection.

You can instead also just consider to dynamically build the SQL string instead. Generating the PreparedStatement placeholders (the ? things) in a loop and and using String#format() to put them in the SQL string. u can also consider to just pass the variables to your runSQLResultSet method and build there instead.

As per the comments, here's an example:

try {
    connection = database.getConnection();
    statement = connection.prepareStatement(SQL);
    setValues(statement, values);

    // ...

.

public static void setValues(PreparedStatement preparedStatement, Object... values) throws SQLException {
    for (int i = 0; i < values.length; i++) {
        preparedStatement.setObject(i + 1, values[i]);
    }
}
BalusC
If I have to pass the variables, it won't really be generic anymore. I want to be able to pass any sql statement with any number of dynamic variables incorporated.
froadie
Just pass them as a `Object[]` or as `Map`.
BalusC
But then how do I process them...? How do I know if it's a String, int, etc....?
froadie
Doesn't matter. Just use `PreparedStatement#setObject()`. An example (and more hints) can be found here: http://balusc.blogspot.com/2008/07/dao-tutorial-data-layer.html Check the `DAOUtil` class example.
BalusC
I can't read the blog as my office blocks all blogs... but thanks for the suggestion! It worked! (Although I used a variable length array - Object ... - instead of an array - Object[])
froadie
The `DAOUtil` class example uses exactly this. I've updated the answer with some relevant copypastes.
BalusC
A: 

If I understand you correctly, you want to use the same query with different variables inserted into the query. You can have your method return the ResultSet like it currently does and pass the variables in as parameters to the method.

then you can put the parameters into the query inside of the method.

public ResultSet getResult(String param1, String param2){
 statement = conn.prepareStatement(yourQuery);// conn must be an open connection
 statement.setString(1,param1);
 statement.setString(2,param2);
 ResultSet rs = statement.execusteQuery();
 return rs;
}

That's a basic example of how you might do something like that if I understood your question correctly.

ChadNC
As I posted in a comment for BalusC's answer - then the method is not really generic anymore. I want to be able to pass any sql statement with any number of dynamic variables (and possible different data types) incorporated.
froadie
+2  A: 
public ResultSet excuteStatement(String statement, Object... params){
  statement = conn.prepareStatement(statement);
  int i = 1;
  for (Object o:params){
    statement.setObject(i++,o);
  }
  ResultSet rs = statement.executeQuery();
  return rs;
}
Paul
PS. Remember to close your ResultSet and preparedstatment.
Paul
Thanks! This is basically what I implemented, as suggested by BalusC in his post and comments
froadie
Bad example. This way you can't close the statement anymore. If you close it, then the resultset will be closed.
BalusC
@BalusC - I used the same basic structure but cached the resultset in a CachedRowSetImpl. I also stored the result of conn.prepareStatement in a PreparedStatement, not a String. But this was the general idea I used
froadie
@BalusC - I agree that i did not give the finer details. But there are many ways to do this... eg. pass through the preparedStatement instead of a string etc.
Paul