对应PreparedStatement相信你们都很熟悉,那么为何要用PreparedStatement呢?也许你会回答PreparedStatement为预处理语句,能够提升数据库执行效率。也许还会回答用PreparedStatement能够防止SQL注入。那么再问下,你以为你对PreparedStatement有足够的了解吗,你在项目中PreparedStatement用对了吗? sql
首先来看下Statement及PreparedStatement执行过程,一个sql语句执行过程当中,将经历这么几个步骤: 数据库
一、传输SQL给数据库 缓存
二、数据库验证并解析SQL 服务器
三、计算Access Plan。数据库会经过检测index,statistics来给出最优的访问计划。 性能
四、根据访问计划进行检索,返回数据。 优化
在上面步骤中,第3步是很是耗时的。所以,为了提升性能,数据库会缓存执行语句以及其Access Plan。这被称为statement cache。在statement cache中,sql语句自己为key,access plan为value。当相同的sql语句被发送过来时,数据库会使用缓存中的access plan以节省cpu时间。 spa
下边看下Statement执行代码: code
1
2
3
4
5
6
7
8
|
Statement statement =connection.createStatement();
String sql1="Select * from test where id=1";
String sql2="Select * from test where id=";
statement.execute(sql1);
statement.execute(sql1);
statement.execute(sql1);
statement.execute(sql2+"2");
statement.execute(sql2+"3");
|
sql1在第一次执行的时候,须要计算执行计划。但在第2和3次执行的时候,会使用缓存好的执行计划,所以后面的sql1不会再从新检验语法与计算执行计划,效率会比第一次高。 对象
sql2却每次都在变化,在cache中,key为整个sql语句,因此每次sql2都没法命中cache,即便它仅仅参数不一样,也必须从新检验语法与计算执行计划,效率天然就低下。 生命周期
强大的数据库会在cache命中上作优化,但复杂的语句仍是避免不了miss。
PreparedStatement的存在是为了不sql2的劣势。看下面code。
1
2
3
4
5
6
|
String sql2="Select * from test where id=?";
PreparedStatement pstmt =connection.prepareStatement(sql2);
pstmt.setInt(1,2);
pstmt.executQuery();
pstmt.setInt(1,3);
pstmt.executQuery();
|
PreparedStatement的生命周期跟Statement同样,在一个数据库链接connection范围内有效,因此说若是一次链接中对于同一个PreparedStatement处理屡次(参数不一样),那么用PreparedStatement是能够提升效率,但大多情景都是屡次链接中处理同一个PreparedStatement,那么就算使用了PreparedStatement也不能提升效率,比较PreparedStatement的生命周期只在Connection中。那么如何正确的使用PreparedStatement呢?
其实不用紧张,告诉你们个好消息,J2EE服务器的链接池管理器已经实现了缓存的使用。J2EE服务器保持着链接池中每个链接准备过的prepared statement列表。当咱们在一个链接上调用preparedStatement时,应用服务器会检查这个statement是否曾经准备过。若是是,这个PreparedStatement会被返回给应用程序。若是否,调用会被转给JDBC驱动程序,而后将新生成的statement对象存入链接缓存。
若是项目未使用数据库链接池怎么办呢,这里只能告诉你,原理你已经很清楚了,本身实现吧。