1、Statement为每一条Sql语句生成执行计划, 如果要执行两条sql语句
select colume from table where colume=1;
select colume from table where colume=2;
会生成两个执行计划,一千个查询就生成一千个执行计划。而生成计划是非常消耗资源的
2、PreparedStatement用于使用绑定变量重用执行计划
select * from xxx.sometable t?where t.id=?;
通过set方法给sql语句按占位符"?"先后顺序赋值,只需要生成一个执行计划,可以重复使用。
?? 当处理批量SQL语句时,这个时候就可以体现PrepareStatement的优势,由于采用Cache机制,则预先编译的语句,就会放在Cache中,下次执行相同SQL语句时,则可以直接从Cache中取出来,效率要比statement高好几倍
PreparedStatement类是Statement类的子类,它直接继承并重写了Statement的方法。PrepardStatement类有两大特点:
特点一:一个PreparedStatement的对象中包含的SQL声明是预编译的,因此当需要多次执行同一条SQL声明时,利用PreparedStatement传送这条SQL声明可以大大提高执行效率。
特点二:PreparedStatement的对象所包含的SQL声明中允许有一个或多个IN参数。创建类PreparedStatement的实例时,IN参数用“?”代替。在执行带参数的SQL声明前,必须对“?”进行赋值,为了对“?”赋值,PreparedStatement类中增添了大量的setXXX方法,完成对IN参数赋值。
⑴创建PreparedStatement对象
与创建Statement类的实例方法类似,创建一个PreparedStatement类的对象也只需在建立连接后,调用Connection类中的方法
public abstract PreparedStatement prepareStatement(String sql) throws SQLException;
例 创建一个PreparedStatement的对象,其中包含一条带参数的SQL声明。
PreparedStatement pstmt=con.prepareStatement("INSERT INTO testTable(id,name) VALUES(?,?)");
⑵IN参数的赋值
PreparedStatement中提供了大量的setXXX方法对IN参数进行赋值。根据IN参数的SQL类型应选用合适的setXXX方法。
例 对上例,若需将第一个参数设为3,第二个参数设为XU,即插入的记录id=3,name="XU",可用下面的语句实现:
pstmt.setInt(1,3);
pstmt.setString(2,"XU");
除了setInt,setLong,setString,setBoolean,setShort,setByte等常见的方法外,PreparedStatement还提供了几种特殊的setXXX方法。
①setNull(int ParameterIndex,int sqlType)
这个方法将参数值赋为Null。sqlType是在java.sql.Types中定义的SQL类型号。
例 语句
pstmt.setNull(1,java.sql.Types.INTEGER);
将第一个IN参数的值赋成Null。
②setUnicodeStream(int Index,InputStream x,int length);
setBinaryStream(int Index,inputStream x,int length);
setAsciiStream(int Index,inputStream x,int length);
当参数的值很大时,可以将参数值放在一个输入流x中,再通过调用上述三种方法将其赋于特定的参数,参数length表示输入流中字符串长度。
每一种数据库都会尽最大努力对预编译语句提供最大的性能优化.因为预编译语句有可能被重复调用.所以语句在被DB的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中(相当于一个涵数)就会得到执行.这并不是说只有一个Connection中多次执行的预编译语句被缓存,而是对于整个DB中,只要预编译的语句语法和缓存中匹配.那么在任何时候就可以不需要再次编译而可以直接执行.而statement的语句中,即使是相同一操作,而由于每次操作的数据不同所以使整个语句相匹配的机会极小,几乎不太可能匹配.比如:
insert into tb_name (col1,col2) values ('11','22');
insert into tb_name (col1,col2) values ('11','23');
即使是相同操作但因为数据内容不一样,所以整个个语句本身不能匹配,没有缓存语句的意义.事实是没有数据库会对普通语句编译后的执行代码缓存.这样每执行一次都要对传入的语句编译一次.
当然并不是所以预编译语句都一定会被缓存,数据库本身会用一种策略,比如使用频度等因素来决定什么时候不再缓存已有的预编译结果.以保存有更多的空间存储新的预编译语句.
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语句是否执行了多次,而且两次之间的差别仅仅是变量的不同。如果仅仅执行了一次的话,它应该和普通的对象毫无差异,体现不出它预编译的优越性。
package com.ys;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
public class DbUtil {
private static String dbDriver = "oracle.jdbc.driver.OracleDriver";
private static String dbURL = "jdbc:oracle:thin:@localhost:1521:orcl";
private static String user = "jhfund";
private static String password = "jhfund";
static {
try {
Class.forName( dbDriver ).newInstance();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static Connection loadConnection() throws Exception{
Connection connection =
DriverManager.getConnection(dbURL, user, password);
return connection;
}
public static void close(Connection connection) throws Exception{
if(connection!=null)
connection.close();
}
public static void close(Statement statement) throws Exception{
if(statement!=null)
statement.close();
}
public static void close(ResultSet rs) throws Exception{
if(rs!=null)
rs.close();
}
public static void close(PreparedStatement preparedStatement) throws Exception{
if(preparedStatement!=null)
preparedStatement.close();
}
}
package com.ys;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.PreparedStatement;
public class PreparedStatementTest {
public void Add() throws Exception{
String SQL = "insert into student(S_NUM,S_NAME,ID_CARD,ADR) values(?,?,?,?)";
Connection conn = null;
PreparedStatement st = null;
try{
conn = DbUtil.loadConnection();
st = conn.prepareStatement(SQL);
st.setInt(1, "201307043");
st.setDouble(2, "李阳");
st.setString(3,"510724199705181231");
st.setDate(4, "白桥大街15号");
st.execute();
}
catch(Exception e){
throw e;
}
finally{
DbUtil.close(st);
DbUtil.close(conn);
}
}
public void AddBatch()throws Exception{
int a = 1;
double b = 99999.99;
String c = "cat";
java.sql.Date d = new java.sql.Date(2010,1,3);
Connection conn = null;
String SQL = "insert into test(a,b,c,d) values(?,?,?,?)";
PreparedStatement st = null;
try{
conn = DbUtil.loadConnection();
st = conn.prepareStatement(SQL);
for( a = 1;a<1000;a++){
st.setInt(1, a);
st.setDouble(2, b);
st.setString(3,c);
st.setDate(4, d);
st.addBatch();
}
st.executeBatch();
}
catch(Exception e){
throw e;
}
finally{
DbUtil.close(st);
DbUtil.close(conn);
}
}
public void update() throws Exception{
int a = 1;
double b = 10000.00;
String c = "cat";
java.sql.Date d = new java.sql.Date(2010,1,3);
String SQL = "update test set b=?,c=?,d=? where a = ?";
Connection conn = null;
PreparedStatement st = null;
try{
conn = DbUtil.loadConnection();
st = conn.prepareStatement(SQL);
st.setDouble(1, b);
st.setString(2,c);
st.setDate(3, d);
st.setInt(4, a);
st.execute();
}
catch(Exception e){
throw e;
}
finally{
DbUtil.close(st);
DbUtil.close(conn);
}
}
public void del()throws Exception{
int a = 1;
String SQL = "delete test where a = ?";
Connection conn = null;
PreparedStatement st = null;
try{
conn = DbUtil.loadConnection();
st = conn.prepareStatement(SQL);
st.setInt(1, a);
st.execute();
}
catch(Exception e){
throw e;
}
finally{
DbUtil.close(st);
DbUtil.close(conn);
}
}
public void delIN()throws Exception{
String SQL = "delete test where a in ?";
Connection conn = null;
PreparedStatement st = null;
try{
conn = DbUtil.loadConnection();
st = conn.prepareStatement(SQL);
st.setString(1, "(1,2,3)");
st.execute();
}
catch(Exception e){
throw e;
}
finally{
DbUtil.close(st);
DbUtil.close(conn);
}
}
public void query(int a)throws Exception{
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try{
conn = DbUtil.loadConnection();
st = conn.prepareStatement(SQL);
st.setInt(1, a);
rs = st.executeQuery();
}
catch(Exception e){
throw e;
}
finally{
DbUtil.close(rs);
DbUtil.close(st);
DbUtil.close(conn);
}
}
public void query()throws Exception{
query(0);
}
}