【JavaEE进阶】MyBatis表查询

文章目录

  • 一. 使用MyBatis完成数据库的操作
    • 1. MyBatis程序中sql语句的即时执行和预编译
      • 1.1 即时执行(${})
      • 1.2 预编译(#{})
      • 1.3 即时执行和预编译的优缺点
    • 2. 单表的增删改等操作
      • 2.1 增加操作
      • 2.2 修改操作
      • 2.3 删除操作
      • 2.4 like(模糊查询)操作
      • 2.5 实体类中的属性和数据库表中的字段名不一致出现的问题的三种解决方式
    • 3. 多表查询
      • 3.1 多表查询(一对一)
      • 3.2 多表查询(一对多)
  • 二. 动态SQL的使用
    • 1. < if >标签
    • 2. < trim >标签
    • 3. < where >标签
    • 4. < set >标签
    • 5. < foreach >标签
  • 单元测试

在上一篇博客中我们简单了解了MyBatis的创建与使用,接下来我们进一步的学习MyBatis的相关知识。
注:此博客中测试案例所使用的单元测试在文末有教程.

一. 使用MyBatis完成数据库的操作

1. MyBatis程序中sql语句的即时执行和预编译

我们在JDBC中在构造sql语句的时候,常常给字段的值用问号?代替,最后在使用方法对这些?进行赋值,这是预编译
使用预编译的好处可以防止sql注入。当然还有一种sql的执行方式就是即时执行
SQL注入是一种常见的安全漏洞,它利用了未正确过滤或转义用户输入的数据,导致恶意用户可以在执行SQL查询时插入恶意的SQL代码。
下面我们来了解一下MyBatis程序中的即使执行和预编译的构建方式.

1.1 即时执行(${})

就像下面我们写道的根据某个字段查询单个信息的时候,我们传递了参数,在xml文件中对相应的字段进行赋值的时候使用${}这种方式就是构造sql语句即时执行的方式。

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

【JavaEE进阶】MyBatis表查询_第1张图片
我们从运行结果看到,执行的sql语句是直接被赋值的,并没有使用?.

1.2 预编译(#{})

这种写法在程序执行的时候,我们可以看到sql语句中id的值先是被?将位置占着的。这里?表示的是只能是值,而不能是sql语句,这就防止了sql注入。

    <select id="getUserById" resultType="com.example.demo.entity.UserEntity">
        select * from userinfo where id=#{id}
    select>

【JavaEE进阶】MyBatis表查询_第2张图片

1.3 即时执行和预编译的优缺点

即时执行(${}):
优点:

  • 当我们逛淘宝的时候,筛选商品点击价格按照从低到高,这个时候传递的就是SQL命令。从低到高传递的就是asc,从高到低传递的就是desc。使用${}可以实现排序查询,而使用#{}就不能实现排序查询,因为当使用#{}查询时,如果传递的值为String就会加单引号,就会导致sql错误.

缺点:

  • 它的执行不安全,存在sql注入.
  • 在使用${}时,如果传入的参数是字符串类型的数据,还需要再构造sql的语句的时候使用单引号将传入的参数引住'${}'

SQL注入是一种常见的安全漏洞,它利用了未正确过滤或转义用户输入的数据,导致恶意用户可以在执行SQL查询时插入恶意的SQL代码。
查询数据库可以看到用户名和密码都是admin.
【JavaEE进阶】MyBatis表查询_第3张图片
正常情况下,用户只能通过密码来输入.

    //用户登录的场景
    UserEntity login(@Param("username")String username,@Param("password")String password);
    <select id="login" resultType="com.example.demo.entity.UserEntity">
        select * from userinfo where username='${username}' and password='${password}'
    select>
//单元测试代码
@Test
    void login() {
        UserEntity user = userMapper.login("admin","admin");
        System.out.println(user);
    }

【JavaEE进阶】MyBatis表查询_第4张图片
但是非法情况下,我们给password的属性填写一个语句就可以登录成功:

@Test
    void login() {
        UserEntity user = userMapper.login("admin","'or 1='1");
        System.out.println(user);
    }

【JavaEE进阶】MyBatis表查询_第5张图片
由于and的优先级高,先执行前面的结果为false.但是后面的or表示的是两个表达式中只要有一个表达式为真,那么最后的结果就为真,那么1=‘1’,这个表达式就为真.
这就是最简单的SQL注入.

预编译(#{}):
优点:

  • 它的执行是安全的,可以防止sql注入。预编译他会将传入的值当成value来看待,判断这个value是否和数据库中这个字段中的值是否相等,相等就会执行成功,不相等会查找不到.
  • 在使用#{}这种写法的时候,如果我们传递的参数是字符串类型的,我们不需要使用单引号(’ ')将#{}括起来,执行的时候,他会自动给value添加单引号。

缺点:

  • 不能传递SQL命令,当传递SQL命令的时候他会给这个命令自动添加单引号(’ '),但是给SQL命令添加单引号SQL语句就会报错。
//UserMapper类下:
    //传递排序规则
    List<UserEntity> getAllByOrder(@Param("myorder")String myorder);
//UserMapper.xml
	    <select id="getAllByOrder" resultType="com.example.demo.entity.UserEntity">
        select * from userinfo order by id #{myorder}
    </select>
//单元测试
    @Test
    void getAllByOrder() {
        List<UserEntity> list = userMapper.getAllByOrder("desc");
        System.out.println(list);
    }

【JavaEE进阶】MyBatis表查询_第6张图片
当时当我们将#{}换成${},再次运行就会执行成功。

select * from userinfo order by id ${myorder}

【JavaEE进阶】MyBatis表查询_第7张图片
总结:
${}#{}的区别在于替换方式和安全性。${}是简单的字符串替换,直接将参数值拼接到SQL语句中,没有安全处理,存在安全风险和SQL注入风险;而#{}是预编译处理,将参数放入PreparedStatement中,使用占位符进行替换,提供了类型转换、安全处理和预编译功能,更加安全可靠。因此,为了防止SQL注入攻击和保证系统的安全性,推荐使用#{}作为参数占位符。

2. 单表的增删改等操作

在上述博客中,我们简单介绍了