1:Statement
每次都会执行SQL语句,相关数据库都要执行SQL语句的编译。
Statement为一条Sql语句生成执行计划,
如果要执行两条sql语句
select colume from table where colume=1;
select colume from table where colume=2;
会生成两个执行计划
一千个查询就生成一千个执行计划!
2: PreparedStatement
用于处理动态SQL语句,在执行前会有一个预编译过程,这个过程是有时间开销的,虽然相对数据库的操作,该时间开销可以忽略不计,
但是PreparedStatement的预编译结果会被缓存,下次执行相同的预编译语句时,就不需要编译,只要将参数直接传入编译过的语句执行代码
中就会得到执行,所以,对于批量处理可以大大提高效率。
(1) PreparedStatement接口继承Statement,PreparedStatement 实例包含已编译的 SQL 语句,
所以其执行速度要快于 Statement 对象。
(2)作为 Statement 的子类,PreparedStatement 继承了 Statement 的所有功能。
三种方法**execute**、 **executeQuery** 和 **executeUpdate** 已被更改以使之不再需要参数
3:应该尽可能以PreparedStatement代替Statement,其原因如下:
(1)代码的可读性和可维护性。从代码比较中就应该能看出来:
stmt.executeUpdate("insert into tb_name (col1,col2,col2,col4) values ('"+var1+"','"+var2+"',"+var3+",'"+var4+"')");//stmt是Statement对象实例
perstmt = con.prepareStatement("insert into tb_name (col1,col2,col2,col4) values (?,?,?,?)");
perstmt.setString(1,var1);
perstmt.setString(2,var2);
perstmt.setString(3,var3);
perstmt.setString(4,var4);
perstmt.executeUpdate(); //prestmt是 PreparedStatement 对象实例
(2)PreparedStatement尽最大可能提高性能。
(3)极大的提高了安全性。
恶意SQL语法
String sql = "select * from tb_name where name= '"+varname+"' and passwd='"+varpasswd+"'";
如果我们把[’ or ‘1’ = ‘1]作为varpasswd传入进来.用户名随意,看看会成为什么?
select * from tb_name = '随意' and passwd = '' or '1' = '1';
因为’1’=’1’肯定成立,所以可以任何通过验证。这算比较委婉的,更有甚者把[‘;drop table tb_name;]作为varpasswd传入进来… 关于数据安全方面的内容这里就不做展开讨论了,总之使用PreparedStatement让执行的SQL更安全。
更有甚者:
把[‘;drop table tb_name;]作为varpasswd传入进来,则:
select * from tb_name = ‘随意’ and passwd = ”;drop table tb_name;有些数据库是不会让你成功的,但也有很多数据库就可以使这些语句得到执行.
而如果你使用预编译语句.你传入的任何内容就不会和原来的语句发生任何匹配的关系.只要全使用预编译语句,你就用不着对传入的数据做任何过虑.而如果使用普通的statement,有可能要对drop,;等做费尽心机的判断和过虑.
罗列出PreparedStatement对象在初级开发中几个常用的方法:
1). PreparedStatement.execute()方法:
该语句可以是任何种类的 SQL 语句
execute 方法返回一个 boolean 值,以指示第一个结果的形式。必须调用 getResultSet 或 getUpdateCount 方法来检索结果,并且必须调用 getMoreResults 移动到任何后面的结果。
返回:
如果第一个结果是 ResultSet 对象,则返回 true;如果第一个结果是更新计数或者没有结果,则返回 false
意思就是如果是查询的话返回true,如果是更新或插入的话就返回false了;
2). PreparedStatement.executeQuery()方法:
返回执行查询语句后得到的ResultSet结果集,注意:该结果集永远不能为null。
3). PreparedStatement.executeUpdate()方法:
返回一个int类型的值,该值代表执行INSERT、DELETE以及UPDATE语句后的更新行数。
如果该值为0,则代表SQL语句没有执行成功。
4).PreparedStatement.addBatch(); executeBatch()方法:
将一组参数添加到此 PreparedStatement 对象的批处理命令中。缓存sql语句,然后批量执行!
将一批命令提交给数据库来执行,如果全部命令执行成功,则返回更新计数组成的数组。
用法举例:
1、增加、修改、删除都用execute(),也可用executeUpdate(),针对于INSERT、UPDATE 或 DELETE 语句
public int addAirEnvironmentPresent(M_AirEnviromentPresentDTO airDTO){
int index = 1;
String sql = "insert into airPresent(airForecastPlace,ForecastTime,TSPvalue,remark) values(?,?,?,?)";
try {
ps = conn.prepareStatement(sql);
ps.setString(index++, airDTO.getAirForecastPlace());
ps.setString(index++, airDTO.getForecastTime());
ps.setString(index++, airDTO.getTSPvalue());
ps.setString(index++, airDTO.getRemark());
ps.execute();
} catch (SQLException e) {
e.printStackTrace();
}
return 1;
}
2、查询调用executeQuery(),针对于SELECT语句
public ArrayList getAirEnvironmentPresentAll(){
ArrayList list = new ArrayList();
String sql = "select * from airPresent";
try {
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
while(rs.next()){
dto = new M_AirEnviromentPresentDTO();
dto.setId(rs.getInt("id"));
dto.setAirForecastPlace(rs.getString("airForecastPlace"));
dto.setForecastTime(rs.getString("forecastTime"));
dto.setTSPvalue(rs.getString("tspvalue"));
dto.setRemark(rs.getString("remark"));
list.add(dto);
}
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
关于PreparedStatement.addBatch()方法
Statement和PreparedStatement的区别就不多废话了,直接说PreparedStatement最重要的addbatch()结构的使用.
1.建立链接,(打电话拨号 )
Connection connection =getConnection();
2.不自动 Commit (瓜子不是一个一个吃,全部剥开放桌子上,然后一口舔了)
connection.setAutoCommit(false);
3.预编译SQL语句,只编译一回哦,效率高啊.(发明一个剥瓜子的方法,以后不要总想怎么剥瓜子好.就这样剥.)
PreparedStatement statement = connection.prepareStatement("INSERT INTO TABLEX VALUES(?, ?)");
4.来一个剥一个,然后放桌子上
//记录1
statement.setInt(1, 1);
statement.setString(2, "Cujo");
statement.addBatch();
//记录2
statement.setInt(1, 2);
statement.setString(2, "Fred");
statement.addBatch();
//记录3
statement.setInt(1, 3);
statement.setString(2, "Mark");
statement.addBatch();
//批量执行上面3条语句. 一口吞了,很爽
int [] counts = statement.executeBatch();
//Commit it 咽下去,到肚子(DB)里面
connection.commit();
stmt.addBatch("update TABLE1 set 题目="盛夏话足部保健1" where id="3407"");
stmt.addBatch("update TABLE1 set 题目="夏季预防中暑膳食1" where id="3408"");
stmt.addBatch("INSERT INTO TABLE1 VALUES("11","12","13","","")");
stmt.addBatch("INSERT INTO TABLE1 VALUES("12","12","13","","")");
stmt.addBatch("INSERT INTO TABLE1 VALUES("13","12","13","","")");
stmt.addBatch("INSERT INTO TABLE1 VALUES("14","12","13","","")");
stmt.addBatch("INSERT INTO TABLE1 VALUES("15","12","13","","")");
stmt.addBatch("INSERT INTO TABLE1 VALUES("16","12","13","","")");
stmt.addBatch("INSERT INTO TABLE1 VALUES("17","12","13","","")");
stmt.addBatch("INSERT INTO TABLE1 VALUES("18","12","13","","")");
int [] updateCounts=stmt.executeBatch();
cn.commit();
例如:
public static void execteBatch(Connection conn)throws Exception{
String sql1 = "delete from student where id =3 ";
String sql2 = "delete from student where id =5 ";
String sql3 = "delete from student where id =6 ";
String sql4 = "delete from student where id =7 ";
PreparedStatement pstmt = conn.prepareStatement(sql1);
pstmt.addBatch();
//addBatch(sql2)该方法为继承statement的方法
pstmt.addBatch(sql2);
pstmt.addBatch(sql3);
pstmt.addBatch(sql4);
pstmt.executeBatch();
};