I have a question regarding general use of Prepared Statement along with connection pooling.
Prepared Statements are generally tied to one connection only.In our app
Assuming that this is a multi-threaded application, Connection
objects are typically associated with a single thread at any instant of time. Connection
objects acquired by a thread are not returned to the pool until they are closed. This applies both to the logical connection wrapper (that is typically returned by a DataSource managed by an application server) to the application, as well as to the physical connection. Also, physical connections can be shared across multiple logical connections as long as they are part of the same transaction.
This means that if a logical connection handle is returned to your application, it is not necessary that the underlying physical connection is the same and is being contended for (unless it is part of the same transaction). If your application is expected to handle concurrent users without any hassle, a Connection
object would be created in every thread starting a transaction, and this object would not be contended for, across threads. Under the hood, different physical connections in the pool would be executing the SQL queries associated with the prepared statements, across multiple threads, again without any contention.
This sounds like an unusual way to use your connection pool. Even though the connections are in a pool, they should only be used by one thread at a time. I tend to create the prepared statement and use it very close to the point of creation. Also, some JDBC drivers now support Statement caching which reduces the overhead of using it in this way.
The value of PreparedStatement lies in the ability of the database itself to create an execution plan for the statement that can be reused for arbitrary parameters and thus is generic in nature (of course that requires that you use parameters in your statetment, e.g.
PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES
SET SALARY = ? WHERE ID = ?");
pstmt.setBigDecimal(1, 153833.00);
pstmt.setInt(2, 110592);
If on the other hand you would use string concatenation to paste the parameter values into the SQL code, the database would not be able to build a generic execution plan. Thus it would make no difference if you use a PreparedStatement or Statement, e.g.
PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES
SET SALARY = 1200 WHERE ID = 3");
would not be able to use the advantage of PreparedStatements.
Your question implies, that you want to reuse the PreparedStatement object, which is not necessary. Of course if you can use a PreparedStatement object to update multiple values etc. it is a more efficient use of ressources. Nevertheless the lifespan (or at least usefull lifespan) of the PreparedStatement is tied to the Connection, thus if you call conn.close() the PreparedStatement is rendered useless. Nevertheless most good drivers in a pooling situation reuse the same PreparedStatement objects again. In short, don't cache the PreparedStatement independent of the connection.
You can't return the Connection
to the pool if you plan on using the PreparedStatement
.
In other words: you can only use a PreparedStatement
constructed from a Connection
that you currently have.
One way around this is to maintain a cache where connections are mapped to prepared statements. When you get a connection from the pool check if it is mapped to the prepared statement that is to be executed. If not, pass the prepared statement to the JDBC driver so that it is compiled. Then map it to the connection. The downside of this approach is that more than one connection might get copies of the same prepared statement. But it seems that this is what some J2EE servers do.