Mybatis Mapper XML文件-参数(Parameters)

在之前的所有语句中,你看到了简单参数的例子。参数在MyBatis中是非常强大的元素。对于简单的情况,也就是90%的情况,它们并没有太多的复杂性,例如:

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

上面的示例展示了一个非常简单的命名参数映射。参数类型被设置为 int,所以参数可以使用任何名称。原始的或简单的数据类型,如 Integer 和 String,并没有相关的属性,因此会完全替换参数的值。然而,如果你传入一个复杂对象,那么行为就有些不同。例如:

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

如果传入一个类型为 User 的参数对象到该语句中,会查找 id、username 和 password 属性,并将它们的值传递给 PreparedStatement 参数。

那对于将参数传递到语句中来说确实非常简单。但是参数映射还有许多其他功能。

首先,和 MyBatis 的其他部分类似,参数可以指定更具体的数据类型。

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

和 MyBatis 的其他部分一样,javaType几乎总能从参数对象中确定,除非该对象是HashMap。在这种情况下,应该指定javaType以确保使用正确的TypeHandler。

注意:如果将null作为值传递,那么JDBC要求对所有可空列都提供JDBC类型。你可以通过阅读PreparedStatement.setNull()方法的JavaDocs来自行了解这一点。

为了进一步自定义类型处理,你还可以指定一个特定的TypeHandler类(或别名),例如:

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

确实,看起来已经有些冗长了,但事实上你很少需要设置这些参数。

对于数值类型,还有一个numericScale属性用于确定有多少位小数是相关的。

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

最后,mode属性允许您指定IN、OUT或INOUT参数。如果参数是OUT或INOUT,参数对象的实际值将被修改,就像你调用输出参数一样。如果mode=OUT(或INOUT)并且jdbcType=CURSOR(即Oracle的REFCURSOR),您必须指定一个resultMap来将ResultSet映射到参数的类型。请注意,此处的javaType属性是可选的,如果使用CURSOR作为jdbcType,并且将其留空,则它会自动设置为ResultSet。

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

MyBatis还支持更高级的数据类型,如structs,但是在注册出参数时必须告诉语句类型名称。例如(再次强调,在实际应用中不要打破行):

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

尽管有这些强大的选项,大多数情况下你只需指定属性名,MyBatis会自动处理其余部分。最多,你只需为可空列指定jdbcType。

#{firstName}
#{middleInitial,jdbcType=VARCHAR}
#{lastName}
String 替换

默认情况下,使用#{}语法将导致MyBatis生成PreparedStatement属性,并安全地将值设置到PreparedStatement参数(例如?)中。虽然这样更安全、更快速,并且通常是首选的方式,但有时您只想直接将一个未修改的字符串注入到SQL语句中。例如,在ORDER BY语句中,您可能会这样使用:

ORDER BY ${columnName}

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

字符串替换在SQL语句中的元数据(例如表名或列名)是动态的时候非常有用,例如,如果你想根据表的任何一个列进行查询,而不是编写如下的代码:

@Select("select * from user where id = #{id}")
User findById(@Param("id") long id);

@Select("select * from user where name = #{name}")
User findByName(@Param("name") String name);

@Select("select * from user where email = #{email}")
User findByEmail(@Param("email") String email);

// and more "findByXxx" method

你只需要写成:

@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String value);

其中${column}将直接替换,而#{value}将被"准备"。因此,你可以通过以下方式完成相同的工作:

User userOfId1 = userMapper.findByColumn("id", 1L);
User userOfNameKid = userMapper.findByColumn("name", "kid");
User userOfEmail = userMapper.findByColumn("email", "noone@nowhere.com");

这个想法同样适用于替换表名。

注意:接受用户输入,并以这种方式未经修改地提供给语句是不安全的。这会导致潜在的SQL注入攻击,因此你应该要么禁止用户在这些字段中输入,要么始终进行自己的转义和检查。

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值