views:

461

answers:

4

Hi.

I'm using the Jdbc template and want to read from the database using prepared statements. I iterate over many lines in a csv file and on every line I execute some sql select queries with it's values.

Now I want to speed up my reading from the database but I just can't get the Jdbc template to work with prepared statements. Actually I even don't know how to do it.

There is the PreparedStatementCreator and the PreparedStatementSetter. As in this example both of them are created with anonymous inner classes. But inside the PreparedStatementSetter class I don't have access to the values I want to set in the prepared statement.

Since I'm iterating through a csv file I can't hard code them as a String because I don't know them. I also can't pass them to the PreparedStatementSetter because there are no arguments for the constructor. And setting my values to final would be dumb too.

I was used to the creation of prepared statements being fairly simple. Something like

PreparedStatement updateSales = con.prepareStatement(
    "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? ");
updateSales.setInt(1, 75); 
updateSales.setString(2, "Colombian"); 
updateSales.executeUpdate():

as in the Java tutorial. But unfortunately working with the jdbc template really is a pain so far.

Your help would be very appreciated.

+1  A: 

Try the following:

PreparedStatementCreator creator = new PreparedStatementCreator() {
    @Override
    public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
        PreparedStatement updateSales = con.prepareStatement(
        "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? ");
        updateSales.setInt(1, 75); 
        updateSales.setString(2, "Colombian"); 
        return updateSales;
    }
};
Kevin
This would work, but the values I want to set are outside the inner anonymous class. Inside the class should be something like `updateSales.setString(2, fileRow.getName())` but I can't access `fileRow` form inside the class.
Bernhard V
mark the var fileRow as final
daedlus
A: 

I'd factor out the prepared statement handling to at least a method. In this case, because there are no results it is fairly simple (and assuming that the connection is an instance variable that doesn't change):

private PreparedStatement updateSales;
public void updateSales(int sales, String cof_name) throws SQLException {
    if (updateSales == null) {
        updateSales = con.prepareStatement(
            "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ?");
    }
    updateSales.setInt(1, sales);
    updateSales.setString(2, cof_name);
    updateSales.executeUpdate();
}

At that point, it is then just a matter of calling:

updateSales(75, "Colombian");

Which is pretty simple to integrate with other things, yes? And if you call the method many times, the update will only be constructed once and that will make things much faster. Well, assuming you don't do crazy things like doing each update in its own transaction...

Note that the types are fixed. This is because for any particular query/update, they should be fixed so as to allow the database to do its job efficiently. If you're just pulling arbitrary strings from a CSV file, pass them in as strings. There's also no locking; far better to keep individual connections to being used from a single thread instead.

Donal Fellows
For queries that return a single value, it's pretty easy to use this technique too. The main complexity comes when you have queries that return many values; either return a `ResultSet` then or pass in a callback that will handle each returned row (with the values broken out of the `ResultSet` of course).
Donal Fellows
Sorry, but I don't know what that has got to do with my jdbc template problem. I can't feed a jdbc template query with a PreparedStatement. It seems that I need a `PreparedStatementCreator` or a `PreparedStatementSetter`.
Bernhard V
+2  A: 

By default, the JDBCTemplate does its own PrepareStatement internally, if you just use the .update(String sql, Object ... args) form. Spring, and your database, will manage the compiled query for you, so you don't have to worry about opening, closing, resource protection, etc. One of the saving graces of Spring.

mezmo
But I want to perform a select on the database, not an update. In the Spring reference http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/jdbc/core/JdbcTemplate.html is written, that with `update` only an insert, update or delete can be performed.
Bernhard V
A: 

I've tried a select statement now with a PeparedStatement from the PreparedStatement class. But it turned out that it was not faster than the Jdbc template. Maybe -- as mezmo suggested -- automatically creates prepared statements.

Anyway, the reason for my sql selects being so slow was another one. In the WHERE clause I always used the operator LIKE, when all I wanted to do was finding an exact match. As I've found out LIKE searches for a pattern and therefore is pretty slow.

I'm using the operator = now and it's much faster.

Bernhard V