上篇看了简单的增删改查标签的使用及官网的介绍,第一次见那么全面的官网,点赞!
今天继续记录下细化的一些特性。
一、参数
在xml中,参数是很常用的,每一个语句都用到参数,大多数的情况下,我们你只须简单指定属性名,顶多要为可能为空的列指定 jdbcType,其他的事情交给 MyBatis 自己去推断就行了吗,比如下面:
<updateid="updateByPrimaryKey"parameterType="com.xing.generator.model.User">updateusersetuserName=#{username,jdbcType=VARCHAR}, passWord=#{password,jdbcType=VARCHAR}, realName=#{realname,jdbcType=VARCHAR} whereid=#{id,jdbcType=INTEGER} </update>
我们就指定了一个jdbcType=VARCHAR,其他的都交给Mybatis框架自己默认就好。不过也可以了解下在复杂的场景下可以使用哪些属性。
<selectid="selectUsers"resultType="User">selectid, username, passwordfromuserswhereid=#{id} </select>
上面的这个示例说明了一个非常简单的命名参数映射。鉴于参数类型(parameterType)会被自动设置为 int,这个参数可以随意命名。原始类型或简单数据类型(比如 Integer 和 String)因为没有其它属性,会用它们的值来作为参数。
然而,如果传入一个复杂的对象,行为就会有点不一样了。比如:
<insertid="insertUser"parameterType="User">insertintousers (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语句会变为
selectcount(*) fromuserwhereage='23'
这样做更安全,更迅速,通常也是首选做法.
不过有时你就是想直接在 SQL 语句中直接插入一个不转义的字符串。
# 比如 ORDER BY 子句,这时候你可以:
ORDERBY${columnName}
# 再比如 替换表名的情况 同样适合用
selectcount(*) from${tableName} whereage='100'
结论就是:${value} 会被直接替换,而 #{value} 会使用 ? 预处理。
$会导致潜在的 SQL 注入攻击。因此,要么不允许用户输入这些字段,要么自行转义并检验这些参数,动态参数还是要用#。
总结:
参数一般情况下不需要刻意指定,Mybatis根据参数类型会自动映射对应的类型,也可以指定一个jdbcType,其他的交给Mybatis搞就可以。
$ 和 # 的区别,# 相当于是使用了预处理,调用preparedStatement的setString方法传入参数可以防止sql注入,安全性更高。$会将传入的内容替换,注意此处是直接替换,不会加上引号,如果是如表名、字段名等写死的字段不让用户输入,那可以用$,不然会有sql注入的安全风险。