mybatis中的参数及#{}和${}区别

http://www.mybatis.org/mybatis-3/sqlmap-xml.html#Parameters

Parameters

In all of the past statements, you've seen examples of simple parameters. Parameters are very powerful elements in MyBatis. For simple situations, probably 90% of the cases, there's not much to them, for example:

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

简单参数,参数名可以任意定义.

The example above demonstrates a very simple named parameter mapping. The parameterType is set to int, so therefore the parameter could be named anything. Primitive or simple data types such as Integer and String have no relevant properties, and thus will replace the full value of the parameter entirely. However, if you pass in a complex object, then the behavior is a little different. For example:

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

If a parameter object of type User was passed into that statement, the id, username and password property would be looked up and their values passed to a PreparedStatement parameter.

That's nice and simple for passing parameters into statements. But there are a lot of other features of parameter maps.

First, like other parts of MyBatis, parameters can specify a more specific data type.

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

Like the rest of MyBatis, the javaType can almost always be determined from the parameter object, unless that object is a HashMap. Then the javaType should be specified to ensure the correct TypeHandler is used.

NOTE The JDBC Type is required by JDBC for all nullable columns, if null is passed as a value. You can investigate this yourself by reading the JavaDocs for the PreparedStatement.setNull() method.

To further customize type handling, you can also specify a specific TypeHandler class (or alias), for example:

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

So already it seems to be getting verbose, but the truth is that you'll rarely set any of these.

For numeric types there's also a numericScale for determining how many decimal places are relevant.

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

Finally, the mode attribute allows you to specify IN, OUT or INOUT parameters. If a parameter is OUT or INOUT, the actual value of the parameter object property will be changed, just as you would expect if you were calling for an output parameter. If the mode=OUT (or INOUT) and the jdbcType=CURSOR (i.e. Oracle REFCURSOR), you must specify a resultMap to map the ResultSet to the type of the parameter. Note that the javaType attribute is optional here, it will be automatically set to ResultSet if left blank with a CURSOR as the jdbcType.

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

MyBatis also supports more advanced data types such as structs, but you must tell the statement the type name when registering the out parameter. For example (again, don't break lines like this in practice):

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

Despite all of these powerful options, most of the time you'll simply specify the property name, and MyBatis will figure out the rest. At most, you'll specify the jdbcType for nullable columns.

#{firstName}
#{middleInitial,jdbcType=VARCHAR}
#{lastName}

String Substitution

By default, using the #{} syntax will cause MyBatis to generate PreparedStatement properties and set the values safely against the PreparedStatementparameters (e.g. ?). While this is safer, faster and almost always preferred, sometimes you just want to directly inject an unmodified string into the SQL Statement. For example, for ORDER BY, you might use something like this:

ORDER BY ${columnName}

Here MyBatis won't modify or escape the string.

NOTE It's not safe to accept input from a user and supply it to a statement unmodified in this way. This leads to potential SQL Injection attacks and therefore you should either disallow user input in these fields, or always perform your own escapes and checks.

http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html#Parameters

参数(Parameters)

前面的所有语句中你所见到的都是简单参数的例子,实际上参数是 MyBatis 非常强大的元素,对于简单的做法,大概 90% 的情况参数都很少,比如:

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

上面的这个示例说明了一个非常简单的命名参数映射。参数类型被设置为 int,这样这个参数就可以被设置成任何内容。原生的类型或简单数据类型(比如整型和字符串)因为没有相关属性,它会完全用参数值来替代。然而,如果传入一个复杂的对象,行为就会有一点不同了。比如:

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

如果 User 类型的参数对象传递到了语句中,id、username 和 password 属性将会被查找,然后将它们的值传入预处理语句的参数中。

这点相对于向语句中传参是比较好的,而且又简单,不过参数映射的功能远不止于此。

首先,像 MyBatis 的其他部分一样,参数也可以指定一个特殊的数据类型。

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

像 MyBatis 的剩余部分一样,javaType 通常可以由参数对象确定,除非该对象是一个 HashMap。这时所使用的 TypeHandler 应该明确指明 javaType。

NOTE 如果一个列允许 null 值,并且会传递值 null 的参数,就必须要指定 JDBC Type。阅读 PreparedStatement.setNull() 的 JavaDocs 文档来获取更多信息。

为了以后定制类型处理方式,你也可以指定一个特殊的类型处理器类(或别名),比如:

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

尽管看起来配置变得越来越繁琐,但实际上,很少需要去设置它们。

对于数值类型,还有一个小数保留位数的设置,来确定小数点后保留的位数。

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

最后,mode 属性允许你指定 IN,OUT 或 INOUT 参数。如果参数为 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 也支持很多高级的数据类型,比如结构体,但是当注册 out 参数时你必须告诉它语句类型名称。比如(再次提示,在实际中要像这样不能换行):

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

尽管所有这些选项很强大,但大多时候你只须简单地指定属性名,其他的事情 MyBatis 会自己去推断,顶多要为可能为空的列指定 jdbcType。

#{firstName}
#{middleInitial,jdbcType=VARCHAR}
#{lastName}

字符串替换

默认情况下,使用 #{} 格式的语法会导致 MyBatis 创建 PreparedStatement 参数并安全地设置参数(就像使用 ? 一样)。这样做更安全,更迅速,通常也是首选做法,不过有时你就是想直接在 SQL 语句中插入一个不转义的字符串。比如,像 ORDER BY,你可以这样来使用:

ORDER BY ${columnName}

这里 MyBatis 不会修改或转义字符串。

NOTE 用这种方式接受用户的输入,并将其用于语句中的参数是不安全的,会导致潜在的 SQL 注入攻击,因此要么不允许用户输入这些字段,要么自行转义并检验。

最后,对于mybatis中#和$绑定参数的区别做个总结,避免以后类似的问题发生。

  1. #{}将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #{id},如果传入的值是111,那么解析成sql时的值为order by “111”, 如果传入的值是id,则解析成的sql为order by “id”。

  2. ${}将传入的数据直接显示生成在sql中。如:order by 
    ${id},如果传入的值是111,那么解析成sql时的值为order by 111, 如果传入的值是id,则解析成的sql为order 
    by id。

  3. #方式能够很大程度防止sql注入。

  4. $方式无法防止Sql注入。

  5. $方式一般用于传入数据库对象,例如传入表名.

  6. 一般能用#的就别用$.

   #{}: 解析为一个 JDBC 预编译语句(prepared statement)的参数标记符,一个 #{ } 被解析为一个参数占位符 。

   ${}: 仅仅为一个纯碎的 string 替换,在动态 SQL 解析阶段将会进行变量替换。

  name-->cy

 eg:  select id,name,age from student where name=#{name}   -- name='cy'

       select id,name,age from student where name=${name}    -- name=cy

猜你喜欢

转载自blog.csdn.net/gaoshan12345678910/article/details/81507609