MyBatis查询数据库(3)

2023年 9月 24日 62.3k 0

 前言🍭

❤️❤️❤️Spring专栏更新中,各位大佬觉得写得不错,支持一下,感谢了!❤️❤️❤️

Spring + Spring MVC + MyBatis专栏

前面我们讲解了MyBatis增删改查基本操作,下面我们来深入了解MyBatis其中不同和需要注意的地方。

一、查询操作🍭

1、单表查询🍉

下面我们来实现⼀下根据用户 id 查询用户信息的功能

UserController 实现代码如下:

//url 路径名直接全部小写即可
    @RequestMapping("/getuserbyid")
    public Userinfo geUserById(Integer id){
        if (id==null)
            return null;
        return userService.getUserById(id);
    }

UserMapper 实现代码如下:

/**
     * 根据用户id查询用户信息
     * @param id
     * @return
     */
    Userinfo getUserById(@Param("id") Integer id);

UserMapper.xml 实现代码如下:


        select * from userinfo where id=${id}

Ⅰ、参数占位符 #{} 和 ${}🍓

  • #{}:预编译处理。
  • ${}:字符直接替换。

预编译处理是指:MyBatis 在处理#{}时,会将 SQL 中的 #{} 替换为?号,使用 PreparedStatement 的 set 方法来赋值。直接替换:是MyBatis 在预处理 时,∗∗就会把{} 时,**就会把 时,∗∗就会把{} 替换成变量的值。**

上面代码我们使用的是${},去传递Integer(整数)类型的参数时,是没有问题的,但如果传递的是String类型的话,程序就会报错。

image.png

下面我们通过 根据用户名查询用户(getUserByName)来看看

image.png

这就直接报错了,说是没有admin这个用户,这是因为${}是直接替换值(不会管你是什么类型,都直接替换),而SQL语句中字符串需要使用单引号,这就会查询不到,报错。

image.png

正确SQL:

image.png

两者区别总结:

1、``#{}:安全参数占位符

  • #{}是MyBatis的预编译语句中的参数占位符,用于传递参数值。它会自动进行参数值的类型转换和防止SQL注入攻击。
  • 在使用#{}时,MyBatis会将参数值通过JDBC的PreparedStatement接口进行预编译,参数值会被当做字符串类型处理,然后由JDBC驱动来负责将其转换成对应的数据库类型,这样可以避免SQL注入问题。
  • 例子:SELECT * FROM users WHERE id = #{userId}

2、``${}:字符串替换占位符

  • 是字符串替换占位符,用于直接将参数的值替换到SQL语句中。在使用{}是字符串替换占位符,用于直接将参数的值替换到SQL语句中。在使用是字符串替换占位符,用于直接将参数的值替换到SQL语句中。在使用{}时,参数值会被直接替换进SQL语句中,不会进行预编译或类型转换。
  • 由于直接替换参数值到SQL语句中,可能存在SQL注入的风险,因此不建议在动态SQL中使用{}直接替换参数值到SQL语句中,可能存在SQL注入的风险,因此不建议在动态SQL中使用直接替换参数值到SQL语句中,可能存在SQL注入的风险,因此不建议在动态SQL中使用{}来传递用户输入的参数。
  • 例子:SELECT * FROM users WHERE id = ${userId}

那这为什么还有${}去传递参数呢?全部使用#{}不是更好?

Ⅱ、${}优点🍓

image.png

在进行排序时(需要传递关键字时)需要使用到${},而 #{sort} 就不能实现排序查询了,因为使用 #{sort} 查询时, 如果传递的值为 String 则会加单引号,就会导致 sql 错误。

UserMapper接口:

//根据id查询用户 并且进行排序
    List getAllByOrder(@Param("order") String order);

UserMapper.xml:


        select * from userinfo order by id ${order}

单元测试:

@Test
    void getAllByOrder() {
        List list = userMapper.getAllByOrder("asc");
        System.out.println(list);
 
    }

单元测试成功:

image.png

Ⅲ、SQL 注入问题 🍓

UserMapper接口:

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

UserMapper.xml:


        select *from userinfo where usernaem='${username}' and password='${password}'

因为${}是直接引用,所以我们加上了单引号。 这样就和使用#{}是一样的了

单元测试:

@Test
    void login() {
        String username="2";
        String password="2";
        Userinfo userinfo=userMapper.login(username,password);
        System.out.println("用户登录"+(userinfo==null?"失败":"成功"));
    }

可以看到此时用户是登录成功的:

image.png

但是这样写有SQL注入的风险,我们修改代码如下,然后运行代码

@Test
    void login() {
        String username="2";
        String password="'or 1 ='1";
        Userinfo userinfo=userMapper.login(username,password);
        System.out.println("用户登录"+(userinfo==null?"失败":"成功"));
    }

单元测试:

image.png

可以看到上面单元测试失败了,但仔细看,是因为返回了5个Userinfo对象,但我只需要接收一个

所以报错了,如果接受的是List

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论