MyBatis单表查询——参数占位符${}和#{}、SQL注入、like查询

目录

前言: 

1、参数占位符:${}和#{}

2、SQL注入

 3、${}的优点

小结:$  VS  #:

4、like查询

 解决方案,使用MySQL的内置函数concat()来处理


前言: 

        以下文章,对于没有接触过Mybatis的小伙伴来说,需要看完这篇文章才可以继续向下执行:http://t.csdn.cn/nGTFZ

其次,我们为了更好地观察出现的问题,可以在配置文件中,配置打印MyBatis的执行SQL:

# 配置打印 MyBatis 执行的 SQL
logging:
  level:
    com:
      example:
        demo: debug

1、参数占位符:${}和#{}

我们在mapper的.xml文件中,进行数据库的SQL语句编写时,通常会使用${}和#{}作为参数占位符,例如:

${}:

接口:

Userinfo getById(@Param("id") Integer id);

UserMapper.xml中: 

    <select id="getUserById" resultType="com.example.demo.entity.Userinfo">
        select* from userinfo where id = ${id}
    </select>

 #{}:

接口:

Userinfo getByName(@Param("username") String username);

UserMapper.xml中: 

    <select id="getByName" resultType="com.example.demo.entity.Userinfo">
        select * from userinfo where username = #{username}
    </select>

 以上代码是没有问题,但如果当我们在.xml文件中,将${id}改为#{id},将#{username}改为${username}时,我们来测试一下【测试使用的是伪代码】:

@SpringBootTest
class UserMapperTest {

    @Autowired
    private UserMapper userMapper;
   
    @Test
    void getById() {
        Userinfo userinfo = userMapper.getById(1);
        System.out.println("查询结果:" +userinfo);
    }

    @Test
    void getByName() {
        Userinfo userinfo = userMapper.getByName("张三");
        System.out.println("查询结果:" +userinfo);
    }
}

测试结果:

 id查询成功:

 username查询失败:

         从这里,其实就能看到,SQL语句是=张三,而我们在学习数据库操作时就知道,字符串类型的需要用双引号括起来~

我们来看看这里${}和#{}到底是怎么查询的呢?

        使用#{}作为参数占位符时, #{}是进行预编译处理,也就是说MyBatis在处理#{}时,会将SQL中的#{}替换为?号,如同JDBC一样,使用PreparedStatement的set方法来赋值。也就是说传过来的参数会用引号括起来,如同sql语句的:

select * from userinfo where id =  '1';

结果:

 

         使用${}作为参数占位符时,${}是进行直接替换,也就是说,MyBatis在处理${}时,直接把${}替换成变量的值,如同上图中直接是username = 张三,如同sql语句的:

${}是直接替换,就会有懂得程序的人借用这个漏洞,乘虚而入——SQL注入

什么是SQL注入呢?


2、SQL注入

假设有一个登录页面【假设数据库中刚好只有一条数据,因为有的配置下,当数据有多条时,可以执行成功,当有的配置下则无法成功】,需要输入用户名和密码:

接口:

Userinfo login(@Param("username") String name, @Param("password") String password);

XML中:

    <select id="login" resultType="com.example.demo.entity.Userinfo">
        select * from userinfo where username = #{username} and password = ${password}
    </select>

 用户名咱们正常使用#{},在密码这里,咱们做一点手脚:使用${}参数占位符~

测试:

    @Test
    void login() {
        String name = "张三";
        String password = " 'xx' or 1=1";
        Userinfo userinfo = userMapper.login(name,password);
        System.out.println("登陆状态:"+(userinfo==null?"失败":"成功"));
    }

结果:

 使用错误的密码居然登陆成功了,这种问题,如果放在实际生活中,大家想想,多恐怖啊!

咱们来看看他实际执行的SQL语句:

控制台,试试看:

为什么说需要一条数据呢?因为,如果有多条,我的这个案例会将多所有的信息全部输出,如下:

 而我们的接收写的是一个对象,而不是用聚合去接收~

结论:用于查询的字段,尽量使用#{}预查询的方式

那${}就没有优点了吗?

还是有的,如下: 


 3、${}的优点

 查询中,带有SQL关键字,需要使用${}

使用#{}会报错:

接口:

List<Userinfo> sortAll(@Param("sort") String userinfo);

 xml:

    <select id="sortAll" resultType="com.example.demo.entity.Userinfo">
        select * from userinfo order by id #{sort}
    </select>

测试:

     @Test
    void sortAll() {
        String sort = "desc";
        List<Userinfo> userinfos = userMapper.sortAll(sort);
        System.out.println(userinfos);
    }

 结果:

 相当于在控制台输入:

 select * from userinfo order by id 'desc';

换成${}再测试:

 

         这样子查询,必须要求传输的值是可以穷举的【如同排序要么是asc,要么是desc】,在使用之前需要对传递的值进行安全性验证~

小结:$  VS  #:

  1. $存在SQL注入的问题,而#不存在
  2. $直接替换,#是预处理

4、like查询

like查询在使用#{}时,会报错:

举例:

接口:

List<Userinfo> likename(@Param("username") String username);

xml:

    <select id="likename" resultType="com.example.demo.entity.Userinfo">
        select * from userinfo where username like "%#{username}%"
    </select>

测试:

    @Test
    void likename() {
        String username = "a";
        List<Userinfo> userinfos = userMapper.likename(username);
        System.out.println(userinfos);
    }

结果:

如同在控制台输入:

 

 正确的控制台应该输入什么:

 解决方案,使用MySQL的内置函数concat()来处理

xml代码:

    <select id="likename" resultType="com.example.demo.entity.Userinfo">
        select * from userinfo where username like concat('%',#{username},'%')
    </select>

运行:

好啦,本期到这里结束 啦,咱们下期再见咯~

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙洋静

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值