【MyBatis系列】Mybatis多表查询与动态SQL

本文深入探讨了MyBatis中的多表查询和动态SQL特性。介绍了参数占位符的区别,强调了SQL注入问题及其防范,讲解了like查询的正确做法,并详细阐述了resultType与resultMap在多表查询中的应用。此外,文章通过实例展示了如何进行一对一和一对多表映射,以及动态SQL的if、trim、where、set和foreach标签的使用,帮助读者掌握MyBatis高级查询技巧。
摘要由CSDN通过智能技术生成

⭐️前面的话⭐️

本篇文章将介绍使用MyBatis进行多表查询以及MyBatis的动态SQL特性。

📒博客主页:未见花闻的博客主页
🎉欢迎关注🔎点赞👍收藏⭐️留言📝
📌本文由未见花闻原创,CSDN首发!
📆首发时间:🌴2022年10月20日🌴
✉️坚持和努力一定能换来诗与远方!
💭参考书籍:无
💬参考在线编程网站:🌐牛客网🌐力扣
博主的码云gitee,平常博主写的程序代码都在里面。
博主的github,平常博主写的程序代码都在里面。
🍭作者水平很有限,如果发现错误,一定要及时告知作者哦!感谢感谢!



封面区


1.较复杂的查询操作

1.1 参数占位符 #{} 和 ${}

#{}:预处理符,如将id=#{2}替换为id=?,然后使用2替换?
${}:替换符,如将id=${2}替换为id=2

两种占位符都可以正常使用的场合:传入的参数类型是数值类型

使用${}

select * from userinfo where id=${
   id}
select * from userinfo where id=2

使用#{}

select * from userinfo where id=#{
   id}
select * from userinfo where id=?

对于这两种参数占位符,个人建议能使用#{}就使用#{},因为${}存在SQL注入的问题,以及如果传入的类型是字符串也会出类型。

只能使用#{}而不能使用${}的场合:传入参数类型为String

使用${}

select * from userinfo where username=${
   username}
//实际执行的语句
Preparing: select * from userinfo where username=张三

但是在sql中通过字符串来查询数据,是需要加上引号的,而使用${}生成的sql并没有带引号,因此不适用于字符串参数的sql。

使用#{}

select * from userinfo where username=#{
   username}
//实际执行语句
select * from userinfo where username=?

由于使用#{}是将目标参数替换为占位符,然后利用JDBC中的占位符机制实现sql语句的填充,所以使用#{}构造的sql是可以正常运行的,并且没有SQL注入的问题。

所以,#{}相比于${},它支持所有类型的参数,包括数值类与字符串类,而${}支持数值类型,不支持字符串类型的参数,但也可以在原来sql里面为${}外面加上一对引号。

select * from userinfo where username='${
   username}'
//实际执行语句
Preparing: select * from userinfo where username='张三'

当传递的参数为字符串类型的时候,虽然加上一对引号,使用${}也可以做到,但是${}存在SQL注入问题,所以仍然不推荐,有关SQL注入后面我们会介绍到。

大部分场合下,使用#{}都可以解决,但还是存在一小部分只能是${}来处理的。

如当我们需要按照升序或者逆序得到数据库查询结果的时候,这种场合就只能使用${},使用#{}会报错,我们来演示一下。

首先,我们在Mapper接口中声明一个方法:作用就是按照排序获取结果集

public List<UserInfo> getOrderList(@Param(value = "order") String order);

我们再去xml文件中去写sql语句:首先我们使用$进行演示

    <select id="getOrderList" resultType="com.example.demo.model.UserInfo">
        select * from userinfo order by createtime ${
   order};
    </select>

我们进行一个单元测试,单元测试代码很简单,就是调用sql,然后得到结果集:

    @Test
    void getOrderList() {
   
        List<UserInfo> userMappers = userMapper.getOrderList("desc");
        System.out.println(userMappers);
    }

单元测试结果:
可以正常查询,得到的结果与预期也是相同的。
1
我们再来试一试使用#{}来构造sql语句:

    <select id="getOrderList" resultType="com.example.demo.model.UserInfo">
        select * from userinfo order by createtime #{
   order};
    </select>

单元测试逻辑与代码不变,我们再来看看单元测试执行的一个结果:
2
我们发现程序报错了,这是因为使用了desc的字符串替换了占位符,而我们所需要的不是一个desc字符串,而是直接一个desc的关键字,所以sql也抛出了语法错误,最终执行的sql为:

select * from userinfo order by createtime ‘desc’;

期望执行的sql为:

select * from userinfo order by createtime desc;

所以在传递sql关键字的时候,不能使用#{},只能使用${}

在这里插入图片描述

1.2SQL注入

SQL注入就是使用${},使用一些特殊的语句,来达到非法获取数据的目的,如不通过正确的密码获取某账户的信息,下面我们来演示一下,就以登录的例子来演示,SQL注入可以在不知道密码的前提下登录成功,并且获取到用户的相关信息。

首先我将数据库只保留一个用户信息,目的是为了方便演示SQL注入问题:
5

第一步,在Mapper接口中定义方法login,返回登录成功的用户对象。

public UserInfo login(@Param("username") String username, @Param(("password")) String password);

第二步,在xml文件中编写SQL语句,我们需要演示SQL注入,所以我们使用${}来构造sql语句。

    <select id="login" resultType="com.example.demo.model.UserInfo">
        select * from userinfo where username='${
   username}' and password='${
   password}';
    </select>

第三步,编写测试类,我们在这个测试类中,传入有注入问题的SQL语句' or 1='1,使得不需要密码就能拿到相关的用户信息。

    @Test
    void login() {
   
        String username = "admin";
        String password = "' or 1='1";

        UserInfo userInfo = userMapper.login(username, password);
        System.out.println(userInfo);
    }

单元测试运行结果:
我们在不知道用户密码的情况下,登录成功,并拿到了用户的信息。
6
最终执行的一段sql语句为:

select * from userinfo where username='admin' and password='' or 1='1';

相当于它在原来条件判断的语句下,后面有加上一个或的逻辑,并且或后面的表达式为true,这样就使得原来的SQL语句中的条件判断部分一定为真,所以就在密码不知道的情况下拿到了用户的基本信息。

所以我们能不使用#{}就不使用${},因为存在SQL注入问题,如果必须使用${}则需要验证一下传递的参数是否合法,比如上面定义排序的sql,传递的参数只能是desc或者是asc,如果不是就不能执行这条SQL,防止SQL注入的发生。

1.3like查询

在Mybatis中使用like查询比较特殊,因为直接使用#{}会报错,而使用${},由于输入的字符串情况很多,无法做到枚举,验证比较困难,无法避免SQL注入问题。

首先,我们来演示使用#{}进行like查询,步骤我就不详细写了,就是查询的步骤。

第一步,声明方法。

public List<UserInfo> getListByName(@Param("username") String username);

第二步,xml写sql。

    <select id="getListByName" resultType="com.example.demo.model.UserInfo">
        select * from userinfo where username like '%#{
   username}%'
    </select>

第三步,单元测试。

    @Test
    void getListByName() {
   
        String username = "a";
        List<UserInfo> list = userMapper.getListByName(username);
        for (UserInfo userInfo : list) {
   
            System.out.println(userInfo)
  • 23
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

未见花闻

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

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

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

打赏作者

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

抵扣说明:

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

余额充值