mybatis中bind的使用
一、介绍
在 mybatis 中,bind
标签允许在 ognl 表达式上下文中创建一个变量并将其绑定到当前上下文,常用于动态 sql 中简化复杂表达式或重复计算。
二、语法
<bind name="变量名" value="ognl表达式"/>
name
:变量名称,后续可直接引用。value
:ognl 表达式,可以是字符串拼接、计算等操作。
三、常见示例
3.1、字符串拼接
在模糊查询中,避免直接在 sql 中拼接 %
,提升可读性:
<select id="searchusers" resulttype="user"> <bind name="pattern" value="'%' + username + '%'"/> select * from users where username like #{pattern} </select>
3.2、动态条件处理(三元表达式)
结合条件判断,简化复杂逻辑:
<select id="getusers" resulttype="user"> <bind name="filtername" value="name != null ? name : '%'"/> select * from users where name like #{filtername} </select>
3.3、避免重复计算
在多次使用同一表达式时,通过 bind
复用:
<select id="calculate" resulttype="double"> <bind name="total" value="price * quantity"/> <bind name="discounted" value="total * (1 - discount)"/> select #{discounted} as final_price </select>
3.4、bind与分页查询
bind经常与分页查询limit一起使用,用来计算limit中的起始条数与分页数。
<select id="pagelistuser" resulttype="com.demo.entity.user" parametertype="java.util.list"> select * from user where name = #{name} <if test="pageno != null and pagesize != null"> <bind name="pageno" value="(pageno-1)*pagesize"/> limit #{pageno},#{pagesize} </if> </select>
pageno
:页码、第几页pagesize
: 每页显示条数
3.5、foreach中使用bind
在 mybatis 的 foreach 循环中,应避免使用 bind 来创建每个迭代的临时变量,因为 bind 的作用域是当前上下文,在循环中会被覆盖。替代方案是在 java 代码中预处理数据,或者直接在表达式中使用循环项和索引。
若实在需要在foreach中使用bind,可以参考文末补充介绍《mybatis foreach里用bind、foreach中使用bind的坑、foreach中动态生成表名》
四、错误示例
4.1、where后面跟着bind
网上看到有些博文写过这样的示例,bind跟在where条件后面,但这是一种错误的写法。
bind
变量仅在当前语句块(如<select>
、<update>
)内有效。
<select id="getusersbynameandage" resulttype="user"> select * from users where name = #{name} and age >= <bind name="minage" value="${minage}" /> </select>
<bind> 必须放在 sql 语句的最前面,不能跟在 where 条件后面。
五、总结
5.1、注意事项
bind
变量仅在当前语句块(如<select>
、<update>
)内有效。- ognl 表达式支持 java 语法,如三元运算符、方法调用等。
- 优先使用
bind
而非直接拼接 sql,以提高安全性和可维护性。
通过灵活使用 bind
,可以显著提升 mybatis 动态 sql 的可读性和简洁性。
补充:mybatis foreach里用bind、foreach中使用bind的坑、foreach中动态生成表名
mybatis foreach里用bind、foreach中使用bind的坑、foreach中动态生成表名
一、前言
在mybatis实际开发中遇到这样一个场景,foreach标签中需要动态生成一个表名,如t0,t1,t2…等等, 可以在dao层传入,也可以在foreach中用bind标签生成,这里我们介绍使用bind生成该变量。
示例如下:
dao层传入[张三、李四]。 mapper.xml中根据传入的列表个数使用foreach进行union all拼接,并且需要动态生成表名 t0、t1等等。最终拼接sql如下:
select * from( select * from user where name='张三' order by id ) t0 union all select * from( select * from user where name='李四' order by id ) t1
二、解决方法/foreach中使用bind
下面为公共的userservice.java、usermapper.java中的代码
userservice.java代码:
@autowired private usermapper usermapper; public list<user> selectbynamelist(){ usermapper.selectbynamelist(arrays.aslist("张三","李四")); return null; }
usermapper.java代码:
public interface usermapper { list<user> selectbynamelist(list<string> namelist); }
2.1、方法一:#传参
usermapper.xml代码
<select id="selectbynamelist" resulttype="com.demo.entity.user" parametertype="java.util.list"> <foreach collection="list" item="item" separator="union all" index="index"> select * from ( select * from user where name = #{item} order by id ) t#{index} </foreach> </select>
日志如下:
==> preparing: select * from ( select * from user where name = ? order by id ) t? union all select * from ( select * from user where name = ? order by id ) t? ==> parameters: 张三(string), 0(integer), 李四(string), 1(integer)
2.2、方法二:$传参 bind生成变量
usermapper.xml代码
<select id="selectbynamelist" resulttype="com.demo.entity.user" parametertype="java.util.list"> <foreach collection="list" item="item" separator="union all" index="index"> <bind name="tablename" value="'t' + index"></bind> select * from ( select * from user where name = #{item} order by id ) ${tablename} </foreach> </select>
日志如下:
==> preparing: select * from ( select * from user where name = ? order by id ) t0 union all select * from ( select * from user where name = ? order by id ) t1 ==> parameters: 张三(string), 李四(string)
注意:
${}
方式传参有sql注入问题,所以确保${}
中的变量没有注入风险。
三、bind变量覆盖问题/错误示例
上面的示例中,我们在foreach标签内使用了bind绑定变量给tablename并且用${tablename}
的方式获取值。如果我们是使用#{tablename}
的方式获取值,会发现每次tablename的值都会是最后一个元素。
错误示例一:
<select id="selectbynamelist" resulttype="com.demo.entity.user" parametertype="java.util.list"> <foreach collection="list" item="item" separator="union all" index="index"> <bind name="tablename" value="'t' + index"></bind> select * from ( select * from user where name = #{item} order by id ) #{tablename} </foreach> </select>
日志文件:
==> preparing: select * from ( select * from user where name = ? order by id ) ? union all select * from ( select * from user where name = ? order by id ) ? ==> parameters: 张三(string), t1(string), 李四(string), t1(string)
错误示例二:循环内重复绑定同名变量
<foreach item="item" collection="list" separator=","> <!-- 错误:每次循环覆盖 previousitem,最终所有值相同 --> <bind name="previousitem" value="item" /> #{previousitem} </foreach>
四、总结
总结:在 mybatis 的 foreach 循环中,应避免使用 bind 来创建每个迭代的临时变量,因为 bind 的作用域是当前上下文,在循环中会被覆盖。替代方案是在 java 代码中预处理数据,或者直接在表达式中使用循环项和索引。
在 mybatis 的 foreach 循环中使用 bind 元素时,需特别注意 bind 的作用域是当前整个 sql 语句,而非单次循环迭代。这意味着在循环内多次使用 bind 绑定同名变量时,后一次会覆盖前一次的值,可能导致逻辑错误。
到此这篇关于mybatis中bind的使用的文章就介绍到这了,更多相关mybatis bind使用内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论