2018-11-13 · Develop

一些 MyBatis 使用中的细节

MyBatis 已成为 Java 后端开发必备技能, MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。本文主要收集一些关于使用 MyBatis 中需要注意的细节。

SQL 列名和关键字重复

这个很好解决,著菊科都提供了 ` 符号。

select `name` from `emp`

列名和 bean 属性名不一样

一般情况来说都是下划线和驼峰命名进行转换, 即:user_iduserId 之间的转换,MyBatis 都有提供解决方案,下面是使用 mybatis-spring-boot-starter 的配置

mybatis.map-underscore-to-camel-case=true

如果不是上面这种简单的转换,建议是使用 ResultMap 进行映射

<resultMap id="userMap" type="com.zuojl.lomall.entity.User">
    <result property="userId" column="user_id"/>
</resultMap>

@Param 参数的作用

当使用 MyBatis 时如果是单个参数就不用这个注解,但是如果是多个参数的话,就需要多个参数才能进行匹配:

User selectByNameAndType(@Param("name") String name, @Param("type") String type);

这样才可以如下调用

select * from user where name = #{name} and type = #{type}

如果不加注解的话调用就只能通过下标进行调用

select * from user where name = #{0} and type = #{1}

# 和 $ 的区别

大部分的情况下使用 #{} 就能满足我们的需求了,但是还是有特殊的场景需要用到 ${},下面就详细讲讲这两者的区别,比如我们有个变量 name 其值是 test 传入 MyBatis

select * from emp where name = #{name}

会转换成

select * from emp where name = 'test'

同样的参数传入

select * from emp order by ${name}

就会被翻译成

select * from emp order by test

简单来说, #{} 是经过预编译的,是安全的,而 ${} 是未经过预编译的,仅仅是取变量的值,是非安全的,存在 sql 注入的危险。# 将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。

什么场景下需要使用 ${} 呢? -- order bylike 、 动态拼接SQL 、 模糊查询等。

上面也说了 ${} 是没有经过预编译的,不安全。在代码中我们就需要添加对SQL的过滤,防止攻击,下面是一个简易版的 SQLFilter。

public class SQLFilter {

    /**
     * SQL注入过滤
     *
     * @param str 待验证的字符串
     */
    public static String sqlInject(String str) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        //去掉'|"|;|\字符
        str = StringUtils.replace(str, "'", "");
        str = StringUtils.replace(str, "\"", "");
        str = StringUtils.replace(str, ";", "");
        str = StringUtils.replace(str, "\\", "");

        //转换成小写
        str = str.toLowerCase();

        //非法字符
        String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alert", "drop"};

        //判断是否包含非法字符
        for (String keyword : keywords) {
            if (str.contains(keyword)) {
                throw new RuntimeException("包含非法字符");
            }
        }
        return str;
    }
}