Mybatis-4-映射文件详解2

138 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

上篇看了简单的增删改查标签的使用及官网的介绍,第一次见那么全面的官网,点赞!

今天继续记录下细化的一些特性。

一、参数

        在xml中,参数是很常用的,每一个语句都用到参数,大多数的情况下,我们你只须简单指定属性名,顶多要为可能为空的列指定 jdbcType,其他的事情交给 MyBatis 自己去推断就行了吗,比如下面:

<update id="updateByPrimaryKey" parameterType="com.xing.generator.model.User">
  update user
set userName = #{username,jdbcType=VARCHAR},
      passWord = #{password,jdbcType=VARCHAR},
      realName = #{realname,jdbcType=VARCHAR}
where id = #{id,jdbcType=INTEGER}
</update>

我们就指定了一个jdbcType=VARCHAR,其他的都交给Mybatis框架自己默认就好。不过也可以了解下在复杂的场景下可以使用哪些属性。

<select id="selectUsers" resultType="User">
select id, username, password
from users
where id = #{id}
</select>

上面的这个示例说明了一个非常简单的命名参数映射。鉴于参数类型(parameterType)会被自动设置为 int,这个参数可以随意命名。原始类型或简单数据类型(比如 Integer 和 String)因为没有其它属性,会用它们的值来作为参数。

然而,如果传入一个复杂的对象,行为就会有点不一样了。比如:

<insert id="insertUser" parameterType="User">
  insert into users (id, username, password)
  values (#{id}, #{username}, #{password})
</insert>

如果 User 类型的参数对象传递到了语句中,会查找 id、username 和 password 属性,然后将它们的值传入预处理语句的参数中,当然也可以自己指定javaType=int:

#{property,javaType=int,jdbcType=NUMERIC}

不指定的话,Mybatis可以根据参数对象的类型确定 javaType。这里特殊情况是该对象是一个 HashMap。这个时候,你需要显式指定 javaType 来确保正确的类型处理器(TypeHandler)被使用。

#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}

对于数值类型,还可以设置 numericScale 指定小数点后保留的位数。

#{height,javaType=double,jdbcType=NUMERIC,numericScale=2}

下面这几句我就没玩过了:

【mode 属性允许你指定 IN,OUT 或 INOUT 参数。如果参数的 mode 为 OUT 或 INOUT,将会修改参数对象的属性值,以便作为输出参数返回。如果 mode 为 OUT(或 INOUT),而且 jdbcType 为 CURSOR(也就是 Oracle 的 REFCURSOR),你必须指定一个 resultMap 引用来将结果集 ResultMap 映射到参数的类型上。要注意这里的 javaType 属性是可选的,如果留空并且 jdbcType 是 CURSOR,它会被自动地被设为 ResultMap。

#{department, mode=OUT, jdbcType=CURSOR, javaType=ResultSet, resultMap=departmentResultMap}

MyBatis 也支持很多高级的数据类型,比如结构体(structs),但是当使用 out 参数时,你必须显式设置类型的名称。比如(再次提示,在实际中要像这样不能换行):

#{middleInitial, mode=OUT, jdbcType=STRUCT, jdbcTypeName=MY_TYPE, resultMap=departmentResultMap}

二、字符串替换

       这里其实就是说的 #{} 和${}了,面试的时候可能会提问这两的区别。

默认情况下,使用 #{} 参数语法时,MyBatis 会创建 PreparedStatement 参数占位符,并通过占位符安全地设置参数(就像使用 ? 一样),如果只传入一个参数的话名字可以随意取。

       #{value}会被传入的内容替换,替换的时候将传入的内容当成字符串,加上引号:

例如传入的内容为123,sql语句会变为

select count(*) from user where age= '23'

这样做更安全,更迅速,通常也是首选做法.

不过有时你就是想直接在 SQL 语句中直接插入一个不转义的字符串。

比如 ORDER BY 子句,这时候你可以:

ORDER BY ${columnName}

再比如 替换表名的情况 同样适合用

select count(*) from ${tableName} where age= '100'

结论就是:${value} 会被直接替换,而 #{value} 会使用 ? 预处理。

$会导致潜在的 SQL 注入攻击。因此,要么不允许用户输入这些字段,要么自行转义并检验这些参数,动态参数还是要用#。

总结:

       参数一般情况下不需要刻意指定,Mybatis根据参数类型会自动映射对应的类型,也可以指定一个jdbcType,其他的交给Mybatis搞就可以。

        和 # 的区别,# 相当于是使用了预处理,调用preparedStatement的setString方法传入参数可以防止sql注入,安全性更高。会将传入的内容替换,注意此处是直接替换,不会加上引号,如果是如表名、字段名等写死的字段不让用户输入,那可以用$,不然会有sql注入的安全风险。

END