MyBatis基础入门4:#{}和${}传参的使用区别

首先我们来解释下MyBaits的中xml文件的常见参数

parameterType:入参类型,一般我们写全类名包装类,如java.lang.String,减少不必要的错误。

如果是POJO对象的话,我们需要从包名开始写。

resultType:返回值类型,规则和入参基本一致。

resultMap:返回映射,当sql查询字段名和pojo的属性名不一致使用,可以通过resultMap将字段名和属性名作一个对应关系 。

接下来我们来看一下MyBatis是如何获取用户传的参数的。首先抛出结论。

Mybatis获取参数值得两种方式:${}和#{},${}的本质是字符串拼接,驱动在向数据库发送sql语句时便已经将sql语句拼接完整,这种方式不安全,会导致sql注入危机;而#{}的本质是占位符赋值,采用预编译的方式,在驱动向数据库发送sql语句时仅提供占位符,在mybatis运行时占位符才会被参数取代,这种方式很安全且大大提高了运行的效率。

下面我们来实测验证,首先我们在主配置文件添加sql输出日志

<settings>
        <!--设置mybatis输出日志-->
        <!--logImpl:表示对日志的控制-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

id          username          birthday       sex     address

14            wkx            2022-04-28     男          保定        这是数据库里的一条记录

我们在目标xml文件中写一条以username为条件的查询语句,请注意我们这里用#{}传参数

<select id="selectByUsername" resultType="com.qcby.entity.User" parameterType="java.lang.String">
  select * from user where username = #{username}
 </select>

我们直接看控制台查询结果

Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 289639718.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@11438d26]
==>  Preparing: select * from user where username = ? 
==> Parameters: wkx(String)
<==    Columns: id, username, birthday, sex, address
<==        Row: 14, wkx, 2022-04-28 16:19:02.0, 男, 保定
<==      Total: 1
User{id=14, username='wkx', birthday=Thu Apr 28 16:19:02 CST 2022, sex='男', address='保定'}
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@11438d26]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@11438d26]
Returned connection 289639718 to pool.

我们可以看到打印的sql语句传的参数是一个“?”,且查询成功为我们返回了一条记录。

接下来我们使用${}来传参

<select id="selectByUsername" resultType="com.qcby.entity.User" parameterType="java.lang.String">
  select * from user where username = ${value}
 </select>
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 243745864.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@e874448]
==>  Preparing: select * from user where username = wkx 
==> Parameters: 
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@e874448]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@e874448]
Returned connection 243745864 to pool.

我们可以看到sql语句直接将我们传的参数打印了出来,但是并没有查询成功,原因是我们查询的是字符串,但是传参时并没有帮我们添加引号。

从上述案例我们便可得到一个结论,#{}传参是占位符,${}传参是字符串的拼接。所以如果我们使用${}传参想要查询成功的话,我们需要手动添加引号,而占位符会自动识别我们传参的类型。

select * from user where username = '${value}'

添加引号之后便可查询成功。

Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 243745864.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@e874448]
==>  Preparing: select * from user where username = 'wkx' 
==> Parameters: 
<==    Columns: id, username, birthday, sex, address
<==        Row: 14, wkx, 2022-04-28 16:19:02.0, 男, 保定
<==      Total: 1
User{id=14, username='wkx', birthday=Thu Apr 28 16:19:02 CST 2022, sex='男', address='保定'}
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@e874448]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@e874448]
Returned connection 243745864 to pool.

接下来我们测试一下${}传参的不安全行为----sql注入

select * from user where username = ${username};   假设我们的目标任务是查询条件是username为“wkx”的记录信息,那么在我们传入其他参数时程序理应报错。

我们首先传入一个正确的参数。

public void search(){
        User user = mapper.selectByUsername("wkx");
        System.out.println(user);
}

 没有任何问题,可以查到我们想要的数据。

 我们来传入这样一个参数:

public void search(){
        User user = mapper.selectByUsername("'wkx' or username = '更新'");
        System.out.println(user);
    }

我们可以看到查询到了两条记录。如果后面拼接的是一条删除语句的话,整个数据库的数据都会有危险。这就是sql注入。 

 当我们使用#{}传参时便不会有这种烦恼。我们可以看到并没有查询到任何信息。

那么我们应该如何选择使用这两种参数传递的方式那。

1.能用#{}就不用${}

2.传入数据是表的字段,如order by 字段排序,这个时候可以用${}

3.在使用${}时,可以使用@param("")给参数重命名

4.模糊查询时也可使用${}

MyBatis基础入门1 - mac下MyBatis在idea的配置 

Mybatis基础入门2-----简单的增删改查 

MyBatis入门基础3 ---代理 

Mybatis基础入门5:动态sql

MyBatis基础入门6:关联映射 

MyBatis基础入门7:注解开发 

MyBatis基础入门8:缓存机制 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值