JDBC(三)—PreparedStatement和Statement的区别和使用(动力节点杜老师)

PreparedStatement相比Statement更安全,能防止SQL注入,因为它使用占位符而非直接拼接字符串。预编译的SQL语句在数据库中只编译一次,多次执行时提高效率并进行类型检查。Statement适用于处理动态SQL,如动态表名、列名或排序方式,但易受SQL注入攻击。
摘要由CSDN通过智能技术生成

背景

学习与反思

异同

  • PreparedStatement和Statement都是JDBC中执行sql的对象,他们都可以执行sql语句,但是后者会给一些人创建出sql注入的条件,而前者不会。
  • prepareStatement :不存在sql注入;效率略高,编译一次,执行多次;在传值后编译时存在类型安全检查。(原理:当历史(预)编译sql语句完全一样时,sql跳过编译,直接执行)
  • statement :存在sql注入问题;编译一次,执行一次

本质

  • 第一步:假如这里使用Statement
String sql2 = ("select * from t_user where LoginName = '"+loginName+"' and LoginPasswd = '"+loginPasswd+"' ");
resultSet = statement.executeQuery(sql2);

Statement采用的是直接拼接的方式,假如说这里的loginName传入的值是aaa,loginPasswd传入的是aaa’ or ‘1’='1,那么sql就变成了

select * from t_user where LoginName ='aaa' and LoginPasswd ='aaa' or '1'='1'

紧接着就被sql执行对象statement带着sql进入数据库进行编译,查询,这样就变成了恒成立,所有的数据都可以查出来,这也就造成了sql注入;所以使用Statement会造成sql注入的本质是:非法sql参数值进入到DBMS(数据库管理系统)参与了sql语句的编译过程,sql参数值中含有的关键字将‘非法字符’拼接到DBMS的编译,改变了sql原来的意思。

  • 第二步:假如这里使用PreparedStatement
   // 创建sql,获取预编译的数据库操作对象
               //sql语句的框架,一个?代表一个占位符,一个?将来接受一个值,
               //占位符不能够用单引号宝齐莱,不然会被人认为是个普通的参数值
            String sql = ("select * from t_user where LoginName = ? and LoginPasswd = ? ");
            //此处sql已经预编译了一次,在进去DBMS执行的时候已经不会再编译了
            prepareStatement = connection.prepareStatement(sql);
//            开始对占位符‘ ?’进行赋值,占位符会根据你选择的类型和填充的数据进行赋值,是setString(),就自动给参数加 '',是setInt()就是数字类型,不会加'',
            //这样一来假如说 传入的是  aaa' or '1'='1  那么就会被当做字符串,一个整体    到sql语句中就是' aaa' or '1'='1 ',是一个整体的值,而不是分开的部分
            prepareStatement.setString(1,loginName);//第一个占位符下标1,放昵称
            prepareStatement.setString(2,loginPasswd);//第二个占位符下标2,放密码
            **//  resultSet = prepareStatement.executeQuery(sql);//此处(sql)应无参,否则sql将再次参与DBMS的编译过程**
            resultSet = prepareStatement.executeQuery();

那么在这里每一个?代表是一个占位符,代表一个值,这样一来假如说 传入的密码是 aaa’ or ‘1’='1 那么就会被当做字符串,传参必须调用setString()方法,在两边各加一个单引号,一个整体 到sql语句中就是**’ aaa’ or ‘1’='1 ',**是一个整体的值,而不是分开的部分。同理还有setInt(),setDouble()等等,最后一句很重要,这里必须是无参,如果在这里又把sql传进去,那么还是会进入数据库参与编译,导致sql注入。

 resultSet = prepareStatement.executeQuery();

Statement的用处

  • 动态的表
    如select * from 表,这个表是动态的,表名肯定是字符串,如果使用PrepareStatement,传入A变成
select * from 'A';

这样肯定是报错的

  • 动态的列
    与上面是同理
  • 动态的排序
    传入asc,desc,也会有这样的问题
    所以此时就需要Statement来帮助我们,正所谓天生我才必有用!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值