PreparedStatement 浅谈

用过Mybatis的都应该了解 #{} ${} 的区别:一般较为常见的回答是:#{}是预编译处理,${}是字符串替换。

所以涉及到了 myabties的底层使用PreparedStatement。但是按照官方说法预编译功能是需要手动开启的。这里以mysql为例:MySQL启用预编译的先决条件是useServerPstmts=true。MySQL是否默认开启和jdbc的版本有很大关系,关系如下:
MySQL Server 4.1之前的版本是不支持预编译的
jdbc驱动是5.0.5之前的版本,默认开启了预编译
jdbc驱动是5.0.5之后的版本,需要手动开启了预编译

我现在使用的mysql是5.7版本,如何打开mysql的查询日志如下
执行
SET GLOBAL log_output=‘FILE’;//将操作记录到文件
SET GLOBAL general_log_file = ‘d:/log/mysql.txt’;日志保存位置
SET GLOBAL general_log = ‘ON’; //开启日志

查看结果
SHOW VARIABLES LIKE "general_log%"
结果如下
在这里插入图片描述
下面开始测试
因为我的jdbc版本比较高,所以是默认关闭的测试代码如下

Class.forName("com.mysql.cj.jdbc.Driver");
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/monster?" +
                "serverTimezone=UTC&characterEncoding=utf-8","root","root");
        PreparedStatement ps = connection.prepareStatement("select * from adress where country = ?");
        ps.setString(1,"中国");
        ResultSet resultSet = ps.executeQuery();
        while(resultSet.next()){
            System.out.println(resultSet.getString("name"));
        }
        resultSet.close();
        connection.close();
	日志如下

在这里插入图片描述
很明显 并没有任何预编译的代码

然后我们修改jdbc连接串,显性开启预编译,代码如下

 Class.forName("com.mysql.cj.jdbc.Driver");
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/monster?" +
                "serverTimezone=UTC&characterEncoding=utf-8&useServerPrepStmts=true&&cachePrepStmts=true","root","root");
        PreparedStatement ps = connection.prepareStatement("select * from adress where country = ?");
        ps.setString(1,"中国");
        ResultSet resultSet = ps.executeQuery();
        while(resultSet.next()){
            System.out.println(resultSet.getString("name"));
        }
        resultSet.close();
        connection.close();

日志如下:
在这里插入图片描述
可以看到有预编译的操作
故而我们查看jdbc代码可知
在这里插入图片描述
真正的预编译,是需要参数支持的。
所以不能说 PreparedStatement就是预编译。那么问题来了,如果PreparedStatement不是预编译,那么他是如何防止sql注入的呢,我做了一些简单的sql注入测试,日志如下,代码略
在这里插入图片描述
根据这个特点我们追踪到
ps.setString(1,“中国”);代码,他到底做了什么操作,代码如下
在这里插入图片描述
F7 进入可知
在这里插入图片描述
他实际上是做了 两端+单引号处理 来防止sql注入的,并不是预编译的效果,使用?作为占位符替换。
PreparedStatement不是将参数简单拼凑成sql,而是做了一些预处理,将参数转换为string,两端加单引号,将参数内的特殊字符(换行,单双引号,斜杠等)做转义处理,很大限度的避免了sql注入。
所以结论是
在未开启预编译参数时,实际上是字符串处理,打开预编译参数,才是真正的预编译
回到开头,mybaties #{} ${}区别是什么,下面才是比较正确的回答
’#‘相当于对数据 加上 双引号,在未开启预编译参数的情况下,其实是伪处理 ,’$'相当于直接显示数据
如果面试谈到预编译问题,你可以说需要开启预编译参数才是真正的预编译,否则都是PreparedStatement的伪处理。
以上都是个人简介如果不对 请斧正 谢谢

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值