本文主要目的是为mybatis的 include 标签添加扩展属性
当使用mybatis进行单表查询时 可以方便的使用 <include> 标签将定义好的<sql> 节点内容包含进来,具体示例如下
<sql id="t_agent_Base_Column_List">
ID, WORKER_ID, <span style="font-family: Arial, Helvetica, sans-serif;">WORKER_NAME, </span>
WORKER_MAIN_NUM, WORKER_EXT_NUM, SALE_PHONE,
IS_PART_TIME, LAST_LOGIN_TIME, SIGN,
HEAD_PIC,WEI_XIN, WX_EWM,
WEIBO, PRACTIC_CERT, WORK_YEAR,
SERVICE_JSON, SERVICE_AREA, PRAISE_COUNT,
SHOP_VIEW_COUNT, CITY_CODE, AREA_CODE,
AREA_NAME, PLACE_CODE, PLACE_NAME,
SORT_SCORE, VOCAT_SKILL, FEATURES,
LEAD_REPUTABLY, STATUS, VERSION,
INSERT_TIME, UPDATE_TIME, BUSINESS_TYPE,
MANIFESTO, BACKGROUND_IMAGE, TITLE_ID
</sql>
<!-- 根据主键查询 -->
<select id="selectById" resultMap="AgentInfo" parameterType="java.lang.Integer">
SELECT
<include refid="t_agent_Base_Column_List" />
FROM
AGENT_INFO
WHERE
ID = #{id,jdbcType=INTEGER}
</select>
SELECT
A.ID, A.WORKER_ID, A.WORKER_NAME,.....经纪人表的其他字段
B. LEVEL, --经纪人等级
B.SUBJECTS_NUM, --完成科目数
B.LOOK_NUM, --带看数
B.DEAL_NUM --成交数
<span style="white-space:pre"> </span>FROM AGENT_INFO A
LEFT JOIN AGENT_TITLE_INFO B ON A.TITLE_ID=B.ID
WHERE A.ID = #{ID}
<!--AgentInfo 中是所有经纪人表字段 -->
<resultMap id="agentExendMap" type="com.kevin.learning.modules.entity.agent.AgentInfoExtend" extends="AgentInfo">
<result column="LEVEL" property="level" jdbcType="VARCHAR"/>
<result column="SUBJECTS_NUM" property="subjectsNum" jdbcType="VARCHAR"/>
<result column="LOOK_NUM" property="lookNum" jdbcType="VARCHAR"/>
<result column="DEAL_NUM" property="dealNum" jdbcType="VARCHAR"/>
</resultMap>
我们可以看到上面的 sql 语句并不能复用定义好的t_agent_Base_Column_List 这个节点来引用整个T_AGENT字段,而是重新写了一遍,而且 经纪人详情表也没有复用。
下面来看一下我的一个扩展方案 ,因为我们的sql是要查询 经纪人信息,还有经纪人详情的几个字段 ,分别是 AGEN_INFO 表和 AGENT_TITLE_INFO表,看一下做了扩展的配置文件,其实这也是整篇文章唯一想要实现的效果
<select id="selectExtendList" resultMap="agentExendMap" parameterType="map">
select
<include refid="t_agent_Base_Column_List" prefix="A."/>,
<include refid="com.kevin.learning.modules.dao.agenttitle.IAgentTitleInfoDAO.t_agent_info_title_Base_Column_List"
prefix="B."
excludeCols="UPDATE_TIME,INSERT_TIME,STATUS,DESCRIPTION,ID"/>
FROM AGENT_INFO A
LEFT JOIN AGENT_TITLE_INFO B ON A.TITLE_ID=B.ID
WHERE A.ID = #{ID}
</select>
注:另一个 include标签是另一个mapper文件定义的,mybatis支持 引用其他文件的 sql节点
主要做了扩展的地方有两个
1、为 <include>节点添加了 prefix属性,这样在引用这个节点的字段都会加上这个前缀
2、为<include>节点添加 excludeCols属性,mybatis其实是可以引用另一个mapper文件中定义的sql节点的,我们上面引用了经纪人详情表的 base_column_List(包含了该表的所有字段),这个属性中定义的字段是会被排除的,以逗号分隔
结果:我们的 sql 包含的字段是 agent_info表的全部字段 + ( AGENT_TITLE_INFO 表全部字段 - excludeCols中定义的字段 )
level 和 lookNum 是 经纪人详情中的字段,这样就查出来了,同时被排除的 insert_time和update_time就没有查询
实现方法分析
这个改动主要是对源码码的修改是很少的,就只在myabtis启动加载 解析mapper文件时将自己需要的特性添加进去 , 要修改的类是 XMLIncludeTransformer 的 applyInclude方法
mybatis在解析sql时将 include 解析完成 会替换掉 原来的 include 节点
代码的处理部分很简单,就是将 sql节点中的 sql语句加上 prefix,然后将整个 字符串 设置到 DOM节点中 ,这样扩展就完成了, 对了,还有一个地方要改,那就是要对 mybatis的DTD文件做一个小改动,因为启动时会用DTD对mapper的xml进行验证