Prepared Statements along with Connection Pooling

无人久伴 提交于 2019-11-30 20:17:28

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.

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.

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.

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!