JDBC(三)之PreparedStatement(预编译Statement)

    参考资料:http://how2j.cn?p=28607https://blog.csdn.net/qqhjqs/article/details/47262673

    百度百科简介:java.sql包中的PreparedStatement 接口继承了Statement,并与之在两方面有所不同:有人主张,在JDBC应用中,如果你已经是稍有水平开发者,你就应该始终以PreparedStatement代替Statement.也就是说,在任何时候都不要使用Statement。

    一、使用方法

import java.sql.*;

public class PreparedStmt {
    public static void main(String[] args) {
        String driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
        String dbUrl = "jdbc:sqlserver://localhost:1433;DatabaseName=SC";
        String userName = "test";
        String userPwd = "test";
        Connection conn = null;
        PreparedStatement pStmt = null;
        try {
            Class.forName(driverName);
            conn = DriverManager.getConnection(dbUrl, userName, userPwd);
            String sql = "insert into course values(?,?,?,null)";
            pStmt = conn.prepareStatement(sql);//注意是prepareStatement()方法
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        try {
            //设置参数的值
            pStmt.setString(1, "1009");
            pStmt.setString(2, "JDBC教程");
            pStmt.setDouble(3, 3.5);
            pStmt.execute();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if(pStmt != null) pStmt.close();
            if(conn != null) conn.close();
        } catch(SQLException e) {
            e.printStackTrace();
        }
    }
}

    注意:1.设置参数值的地方是JAVA里唯二的基1(从一开始)的地方,另一个是查询语句中的ResultSet也是基1的。

    2.在执行 PreparedStatement 对象之前,必须设置每个 ? 参数的值。这可通过调用 setXxx 方法来完成,其中 Xxx须是与该参数相应的类型。

    二、与Statement相比的优点

    1.Statement 需要进行字符串拼接,可读性和维护性比较差
String sql = "insert into hero values(null,"+"'提莫'"+","+313.0f+","+50+")"

    PreparedStatement 使用参数设置,可读性好,不易犯错

String sql = "insert into hero values(null,?,?,?)";
    2.PreparedStatement尽最大可能提高性能.
    每一种数据库都会尽最大努力对预编译语句提供最大的性能优化,因为预编译语句有可能被重复调用,所以语句在被DB的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中(相当于一个函数)就会得到执行。这并不是说只有一个Connection中多次执行的预编译语句被缓存,而是对于整个DB中,只要预编译的语句语法和缓存中匹配。那么在任何时候就可以不需要再次编译而可以直接执行。而statement的语句中,即使是相同一操作,而由于每次操作的数据不同所以使整个语句相匹配的机会极小,几乎不太可能匹配。比如:
  insertintotb_name(col1,col2)values('11','22');
  insertintotb_name(col1,col2)values('11','23');
  即使是相同操作但因为数据内容不一样,所以整个个语句本身不能匹配,没有缓存语句的意义.事实是没有数据库会对普通语句编译后的执行代码缓存.
3.防止SQL注入式攻,提高安全性
   假设name和passwd是用户传来的数据,有下方语句:
 
String sql="select * from tb_name where name ='" +name +"'and passwd='"+passwd+"'";

 如果我们把['or'1'='1]作为passwd传入进来,用户名随意,则执行的SQL语句会是:

select * from tb_name ='任意字符' and passwd='' or '1'='1';

 因为'1'='1'肯定成立,所以可以任意通过验证.更有甚者把[';drop table tb_name;]作为passwd传入进来,则SQL语句会被改写成:

select * from tb_name ='随意'and passwd='';drop table tb_name;
    有些数据库是不会让你成功的,但也有很多数据库就可以使这些语句得到执行。
    而如果你使用预编译语句,你传入的任何内容就不会和原来的语句发生任何匹配的关系。只要全使用预编译语句,你就用不着对传入的数据做任何过虑。而如果使用普通的statement,有可能要对drop等做费尽心机的判断和过滤。
     SQL注入 攻 击 只 对 Statement有效, 对 PreparedStatement 是无效的; PreparedStatement可以在传入sql后,执行语句前,给参数赋值,避免了因普通的拼接sql字符串语句所带来的安全问题,而且准备sql和执行sql是在两个语句里面完成的,也提高了语句执行的效率 比如单引号会给你加一个转义,加个斜杠。而在数据库里执行的语句可能会是下面这样:
select * from t_user where password='ddd\' or \'1\'=\'1';

    它会把恶意的注入语句预处理为参数。

    注意:和Statement不不同的是,使用PreparedStatement时,是无法直接使用System.out.println(SQL)输出当前执行的SQL语句的,此时输出的结果会是:


    仍然会是你当时定义的String类型的带 ?的SQL语句。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值