bind标签在mybatis官方文档中只有一句话和一个基本例子进行了介绍,下面是官方文档的介绍:
bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。比如:
<select id="selectBlogsLike" resultType="Blog">
<bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
SELECT * FROM BLOG
WHERE title LIKE #{pattern}
</select>
value的值写OGNL表达式,OGNL表达式的使用不做过多说明,如果想在OGNL表达式中使用字符串
- 简单写法:用引号扩起来,到底使用单引号还是双引号是由外层引号决定的。
- 标准写法:用%{’’}或%{""}把表达式括起来,强制转成字符串。
在这里value=后面外层使用的双引号,所以内层单引号括起来的’%‘表示的就是字符串’%’
由上面的例子我们可以知道,bind标签的name属性填写一个参数名,value填写这个参数的值(使用OGNL表达式),bind标签写上后,在标签后面的上下文中使用的和bind标签name值同名的参数,它的值就会被替换为bind标签的value的值。如上面的例子中,在执行这条select语句时,#{pattern}的值就会为"’%’ + _parameter.getTitle() + ‘%’"计算执行后的值。
我在实际做项目的时候,遇到了这样的一种情况,在一条sql语句中,有多个地方需要用到一个同名的参数,而这个参数在这几个地方的值是不一样的。下面是我遇到的情况:
<sql id="queryListWhere">
<where>
<if test="bussinessOppotunityId!=null and bussinessOppotunityId!=''">
and t.bussiness_oppotunity_id = #{bussinessOppotunityId}
</if>
<if test="companyId!=null and companyId!=''">
and t.company_id = #{companyId}
</if>
<if test="languageId!=null and languageId!=''">
and t.language_id = #{languageId}
</if>
<if test="currencyId!=null and currencyId!=''">
and t.currency_id = #{currencyId}
</if>
<if test="supplierId!=null and supplierId!=''">
and t.supplier_id = #{supplierId}
</if>
<if test="paymentConditionId!=null and paymentConditionId!=''">
and t.payment_condition_id = #{paymentConditionId}
</if>
<if test="invoiceTypeId!=null and invoiceTypeId!=''">
and t.invoice_type_id = #{invoiceTypeId}
</if>
<if test="createBy!=null and createBy!=''">
and t.create_by = #{createBy}
</if>
<if test="delFlag!=null and delFlag!=''">
<choose>
<when test="delFlag == '21'">
and t.del_flag = 2
and not exists(select 1 from in_quotation where PURCHASE_CONFIRMATION_ID = t.id and DEL_FLAG <= 2)
</when>
<when test="delFlag == '22'">
and t.del_flag = 2
and not exists(select 1 from in_purchase_contract where purchase_confirmation_id = t.id and del_flag <= 2)
and exists (select 1 from in_quotation where purchase_confirmation_id = t.id and del_flag = '2')
</when>
<otherwise>
and t.del_flag in (${delFlag})
</otherwise>
</choose>
</if>
</where>
</sql>
这个queryListWhere会根据dao接口传递过来的参数来实现条件查询,然后我需要写这样一段代码
<select id="showCount" resultType="map">
select
(select count(*) from in_purchase_confirmation t <include refid="queryListWhere"></include>) waitAudit,
(select count(*) from in_purchase_confirmation t <include refid="queryListWhere"></include>) waitQuote,
(select count(*) from in_purchase_confirmation t <include refid="queryListWhere"></include>) waitContract
from dual
</select>
这段代码的三个地方都引入了queryListWhere,没做修改的情况下,这三个地方都会获取到同样参数值。
在这条语句的情况下,delFlag参数都会从dao接口传来的参数获取到同样的值,这3个子查询会查询到同样的结果。
而我需要在这3个子查询中,delFlag参数的值是不同的。比如我需要在第一个子查询处,delFlag为1;第二个子查询处,delFlag为21;第三个子查询处,delFlag为22。
我曾尝试使用include标签下的property标签来解决这个问题
<select id="showCount" resultType="map">
select
(select count(*) from in_purchase_confirmation t <include refid="queryListWhere"><property name="delFlag" value="1"></property></include>) waitAudit,
(select count(*) from in_purchase_confirmation t <include refid="queryListWhere"><property name="delFlag" value="21"></property></include>) waitQuote,
(select count(*) from in_purchase_confirmation t <include refid="queryListWhere"><property name="delFlag" value="22"></property></include>) waitContract
from dual
</select>
但是发现property标签并没有起到作用,delFlag还是会直接使用dao接口传来的参数。似乎在dao接口有参数传递过来的情况下,property标签就失效了,sql语句中的参数会直接使用dao接口传递过来的参数。
使用bind标签就解决了我的问题,完善后的代码如下:
<select id="showCount" resultType="map">
select
(select count(*) from in_purchase_confirmation t <bind name="delFlag" value="'1'" /> <include refid="queryListWhere"></include>) waitAudit,
(select count(*) from in_purchase_confirmation t <bind name="delFlag" value="'21'" /> <include refid="queryListWhere"></include>) waitQuote,
(select count(*) from in_purchase_confirmation t <bind name="delFlag" value="'22'" /> <include refid="queryListWhere"></include>) waitContract
from dual
</select>
bind标签的name都是delFlag,后写的bind标签会覆盖前面的bind标签