How PreparedStatement greatly improves performance

This article describes how to use prepared statements correctly. Why it can make your application run faster, and also make database operations faster.
 
 
Why are Prepared Statements important? How to use it correctly?
 
Databases have very hard work. They accept SQL queries from many concurrent clients, execute them and return results as fast as possible. Handling statements is an expensive operation, but there are methods like Prepared Statements to minimize this overhead. However, this optimization requires developers to complete. So this article will show you how to use Prepared Statements correctly to optimize database operations.
 
 
How does the database execute a statement?
 
Obviously, I won't write a lot of details here, we'll just focus on the most critical parts. When a database receives a statement, the database engine parses the statement and checks it for syntax errors. Once the statement is properly parsed, the database chooses the best way to execute the statement. Unfortunately this computation is very expensive. The database will first check to see if there are relevant indexes that can help with this, whether or not it will read all the rows in a table. The database counts the data, and then selects the best route. When a query plan is created, the database engine executes it. The generation of the access plan (Access Plan) will take up quite a lot of CPU. Ideally, when we send a statement to the database multiple times, the database should reuse the statement's access plan. This will reduce CPU usage if the scenario has ever been generated. Statement Caches
 

 
 

 
Databases already have similar functionality. They usually cache statements in the following ways. Use the statement itself as the key and store the access plan in the cache corresponding to the statement. This allows the database engine to reuse access plans from previously executed statements. For example, if we send a statement containing SELECT a, b FROM t WHERE c = 2 to the database, the access plan will be cached first. When we send the same statement again, the database reuses the previously used access plan, which reduces CPU overhead.
 
Note that the entire statement is used here as the key. That is, if we send a statement containing SELECT a, b FROM t WHERE c = 3, there will be no corresponding access plan in the cache. This is because "c=3" is not the same as "c=2" which was ever cached. So, for example:
 
for (int i = 0; i < 1000; i++) {
PreparedStatement ps = conn.prepareStatement("select a,b from t where c = " + i);
ResultSet rs = Ps.executeQuery() ;
);
ps.close();
}
 
The cache is not used here because each iteration sends a statement containing a different SQL statement to the database. And each iteration generates a new access plan. Now let's look at the next piece of code:
 
PreparedStatement ps = conn.prepareStatement("select a,b from t where c = ?");
for (int i = 0; i < 1000; i++) {
ps.setInt(1, i);
ResultSet rs = ps.executeQuery() ; rs.close (
);
ps.close(); Good efficiency, the statement sent to the database is a SQL statement with a parameter "?". This way each iteration will send the same statement to the database, just the parameter "c=?" is different. This approach allows the database to reuse the statement's access plan for better efficiency. This can make your application faster and use less CPU, so the database server can serve more people. PreparedStatement and J2EE server When we use J2EE server things get more complicated. Typically, a perpared statement is associated with a single database connection. The prepared statement is also discarded when the database connection is closed. Typically, a thick client will acquire a database connection and hold it until it exits. It creates all parepared statements "eagerly" or "lazily". The "Hungry Man" way creates everything when the app starts. The "lazy" way means that it is only created when it is used. The "hungry" approach causes the app to have a slight delay when it starts up, but once it starts it runs pretty well. The "lazy" approach makes the application start very fast (but doesn't do any preparation), and creates it when it needs to use a prepared statement. In this way, the performance is very unstable during the process of creating all the statements, but once all the statements are created, it will run very well like a "hungry" style application. Please choose the best way according to your needs, is it quick start? Still consistent performance.

 

 
 

 

 
The problem with J2EE applications is that it doesn't work like this, the connection is only held for the duration of the request. That means the prepared statement must be created for every request. This is far from the performance of the thick client that keeps prepared statements all the time. J2EE manufacturers have noticed this problem, and provide a connection pool (ConnectionPool) to avoid this problem. When a J2EE server provides a connection to your application, it doesn't actually give you a real database connection, you just get a wrapper . You can verify this by looking at the class name of the connection you got. It is not a JDBC connection, but a class created by the application server . All JDBC operations are proxied by the application server's connection pool manager. All JDBC ResultSets, statements, CallableStatements, preparedStatements, etc. will be wrapped and returned to the application in the form of a "Proxy Object". When you close the connection, these objects are marked as invalid and collected by the garbage collector. Normally, if you execute close on a database connection, the connection will be closed by the JDBC driver. But we need the database connection to be returned to the connection pool when the J2EE server executes close. We can solve this problem by creating a JDBC Connection proxy class that acts like a real connection. It has a reference to the real connection. When we execute a method on a connection, the proxy forwards the action to the real connection. However, when we close a connection, the connection is not closed, but sent back to the connection pool and can be used by other requests. A prepared statement that has already been prepared will also be reused as a result. J2EE PreparedStatement Cache
 

 

 
 

 
The connection pool manager of the J2EE server has implemented the use of the cache. The J2EE server maintains a list of prepared statements for each connection in the connection pool. When we call preparedStatement on a connection, the application server checks to see if the statement was ever prepared. If so, this PreparedStatement will be returned to the application. If not, the call will be forwarded to the JDBC driver, which will then store the newly generated statement object in the connection cache. The reason each connection has a cache is because: that's how JDBC drivers work. Any prepared statement is returned by the specified connection. If we want to take advantage of this cache, as mentioned earlier, using a parameterized query statement can find the statement that has been used in the cache. Most application servers allow you to adjust the size of the prepared statements cache. SummaryWe should definitely use prepared statements that contain parameterized query statements. This way the database will reuse the prepared access plan. Caching applies to the entire database, so if you schedule all applications to use the same parameterized SQL statement, then your other applications can reuse the prepared statement. This is an advantage of the application server, because all database operations are centralized in the database operation layer (Database Access Layer, including O/R mapping, entity beans, JDBC, etc.). Second, the correct use of prepared statements is also the key to taking advantage of the caching advantages of prepared statements. Since the application can reuse the prepared statement, the number of calls to the JDBC driver is reduced, thereby improving the performance of the application. In this way, you have the efficiency that can be compared with thick clients, but you don't need to maintain a connection all the time.
 

 

 
 

 

 

 
With parameterized prepared statements, your application will have better performance.

 

 

///////////////

 

1.PreparedStatement是预编译的,对于批量处理可以大大提高效率. 也叫JDBC存储过程 
2.使用 Statement 对象。在对数据库只执行一次性存取的时侯,用 Statement 对象进行处理。PreparedStatement 对象的开销比Statement大,对于一次性操作并不会带来额外的好处。 
3.statement每次执行sql语句,相关数据库都要执行sql语句的编译,preparedstatement是预编译得,preparedstatement支持批处理 
4.
Code Fragment 1: 

String updateString = "UPDATE COFFEES SET SALES = 75 " + "WHERE COF_NAME LIKE ′Colombian′"; 
stmt.executeUpdate(updateString); 

Code Fragment 2: 

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

片断2和片断1的区别在于,后者使用了PreparedStatement对象,而前者是普通的Statement对象。 PreparedStatement对象不仅包含了SQL语句,而且大多数情况下这个语句已经被预编译过,因而当其执行时,只需DBMS运行SQL语句, 而不必先编译。当你需要执行Statement对象多次的时候,PreparedStatement对象将会大大降低运行时间,当然也加快了访问数据库的 速度。 
这种转换也给你带来很大的便利,不必重复SQL语句的句法,而只需更改其中变量的值,便可重新执行SQL语句。选择PreparedStatement对 象与否,在于相同句法的SQL语句是否执行了多次,而且两次之间的差别仅仅是变量的不同。如果仅仅执行了一次的话,它应该和普通的对象毫无差异,体现不出 它预编译的优越性。 
5.执行许多SQL语句的JDBC程序产生大量的Statement和PreparedStatement对象。通常认为 PreparedStatement对象比Statement对象更有效,特别是如果带有不同参数的同一SQL语句被多次执行的时候。 PreparedStatement对象允许数据库预编译SQL语句,这样在随后的运行中可以节省时间并增加代码的可读性。 

然而,在Oracle环境中,开发人员实际上有更大的灵活性。当使用Statement或PreparedStatement对象时,Oracle数据库 会缓存(和JDBC缓存是两回事)SQL语句以便以后使用。在一些情况下,由于驱动器自身需要额外的处理和在Java应用程序和Oracle服务器间增加的网络活动,执行 PreparedStatement对象实际上会花更长的时间(因此,使用statement的最好时机是频繁的参数--是参数项目而不是参数的值--变化时的SQL语句)。 

然而,除了缓冲的问题之外,至少还有一个更好的原因使我们在企业应用程序中更喜欢使用PreparedStatement对象,那就是安全性。传递给 PreparedStatement对象的参数可以被强制进行类型转换,使开发人员可以确保在插入或查询数据时与底层的数据库格式匹配。 

当处理公共Web站点上的用户传来的数据的时候,安全性的问题就变得极为重要。传递给PreparedStatement的字符串参数会自动被驱动器忽 略。最简单的情况下,这就意味着当你的程序试着将字符串“D'Angelo”插入到VARCHAR2中时,该语句将不会识别第一个“,”,从而导致悲惨的 失败。几乎很少有必要创建你自己的字符串忽略代码。 

在Web环境中,有恶意的用户会利用那些设计不完善的、不能正确处理字符串的应用程序。特别是在公共Web站点上,在没有首先通过 PreparedStatement对象处理的情况下,所有的用户输入都不应该传递给SQL语句。此外,在用户有机会修改SQL语句的地方,如HTML的 隐藏区域或一个查询字符串上,SQL语句都不应该被显示出来。 
在执行SQL命令时,我们有二种选择:可以使用PreparedStatement对象,也可以使用Statement对象。无论多少次地使用同一个 SQL命令,PreparedStatement都只对它解析和编译一次。当使用Statement对象时,每次执行一个SQL命令时,都会对它进行解析 和编译。 


第一: 

prepareStatement会先初始化SQL,先把这个SQL提交到数据库中进行预处理,多次使用可提高效率。 
createStatement不会初始化,没有预处理,没次都是从0开始执行SQL 

第二: 

prepareStatement可以替换变量 
在SQL语句中可以包含?,可以用ps=conn.prepareStatement("select * from Cust where ID=?"); 
int sid=1001; 
ps.setInt(1, sid); 
rs = ps.executeQuery(); 
可以把?替换成变量。 
而Statement只能用 int sid=1001; 
Statement stmt = conn.createStatement(); 
ResultSet rs = stmt.executeQuery("select * from Cust where ID="+sid); 
来实现。 

第三: 

prepareStatement会先初始化SQL,先把这个SQL提交到数据库中进行预处理,多次使用可提高效率。 
createStatement不会初始化,没有预处理,没次都是从0开始执行SQL

原文地址:https://www.cnblogs.com/Jtianlin/p/4403395.html

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325774456&siteId=291194637