JDBC基础学习(二)—PreparedStatement
一、PreparedStatement介绍
在SQL中包含特殊字符或SQL的关键字(如: ' or 1 or ')时Statement将出现不可预料的结果(出现异常或查询的结果不正确),可用PreparedStatement来解决。
public class StudentDemo{ @Test public void testAddPerson() throws Exception{ Person p = new Person(0,"CCC","SH",22,800); addPerson(p); } @Test public void testqueryPerson() throws Exception{ queryPerson(); } /* * 插入数据 */ public static void addPerson(Person p) throws Exception{ Connection con = null; PreparedStatement ps = null; ResultSet rs = null; try{ // 建立连接 con = JdbcTools.getConnection(); // 创建语句 String sql = "insert into person(id,name,city,age,salary) values(?,?,?,?,?)"; ps = con.prepareStatement(sql); ps.setInt(1,p.getId()); ps.setString(2,p.getName()); ps.setString(3,p.getCity()); ps.setInt(4,p.getAge()); ps.setFloat(5,p.getSalary()); // 执行语句 int i = ps.executeUpdate(); // 处理结果 System.out.println("有" + i + "行受到影响"); }finally{ JdbcTools.releaseResource(con,ps,rs); } } /* * 查询数据 */ public static void queryPerson() throws Exception{ Connection con = null; PreparedStatement ps = null; ResultSet rs = null; try{ //建立连接 con = JdbcTools.getConnection(); //创建语句 String sql = "select id,name,city, age,salary from person"; ps = con.prepareStatement(sql); //执行语句 rs = ps.executeQuery(); //处理结果 while(rs.next()){ System.out.println(rs.getObject("id") + "\t" + rs.getObject("name") + "\t" + rs.getObject("city") + "\t" + rs.getObject("age") + "\t" + rs.getObject("salary")); } } finally{ JdbcTools.releaseResource(con,ps,rs); } } }结果:
二、PreparedStatement的优点
(1)性能
PreparedStatement 能最大可能提高性能。
prepareStatement会先初始化SQL,先把这个SQL提交到数据库中进行预处理,多次使用可提高效率。
createStatement不会初始化,没有预处理,没次都是从0开始执行SQL。
DBServer会对预编译语句提供性能优化。因为预编译语句有可能被重复调用,所以语句在被DBServer的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中就会得到执行。
在statement语句中,即使是相同操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的意义.事实是没有数据库会对普通语句编译后的执行代码缓存.这样每执行一次都要对传入的语句编译一次。
(2)安全性
PreparedStatement可以防止SQL注入攻击,而Statement却不能。
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'肯定成立,所以可以任何通过验证。
而如果你使用预编译语句你传入的任何内容就不会和原来的语句发生任何匹配的关系,只要全使用预编译语句你就用不着对传入的数据做任何过滤。
(3)代码的可读性与可维护性
st.executeUpdate("insert into tb_name (col1,col2,col2,col4) values ('"+var1+"','"+var2+"',"+var3+",'"+var4+"')"); ps = con.prepareStatement("insert into tb_name (col1,col2,col2,col4) values (?,?,?,?)"); ps.setString(1,var1); ps.setString(2,var2); ps.setString(3,var3); ps.setString(4,var4); ps.executeUpdate();
可以看出第一种和第二种的巨大差别。
三、通用的增删改操作
利于PreparedStatement我们可以写一个通用的增删改操作。
/* * 通用的增删改方法 * 执行SQL语句,使用PreparedStatemnt * @param sql 带占位符的sql语句 * @param args 填写SQL占位符的可变参数 */ public static void update(String sql,Object...args){ Connection con = null; PreparedStatement ps = null; ResultSet rs = null; try{ con = JdbcTools.getConnection(); ps = con.prepareStatement(sql); for(int i = 0;i < args.length;i++){ ps.setObject(i + 1,args[i]); } ps.execute(); }catch (Exception e) { e.printStackTrace(); } finally{ JdbcTools.releaseResource(con,ps,rs); } }