关于mybatis扩展的一点想法

Posted 程序员A

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于mybatis扩展的一点想法相关的知识,希望对你有一定的参考价值。

本文主要目的是为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>


但是当我们还需要其他表的一些字段时,那就要去联合查询另一个表的数据了,就不太方便复用 t_agent_Base_Column_List 这个sql节点了,比如说还有一张表存放的是经纪人等级以及经纪人带看记录数等一些信息,我们用的sql语句如下

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}


所需要的resultMap定义如下

<!--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进行验证 

技术分享

技术分享
技术分享
技术分享

技术分享

技术分享
技术分享





























以上是关于关于mybatis扩展的一点想法的主要内容,如果未能解决你的问题,请参考以下文章

关于WEB项目的一点想法

关于团队项目的一点想法

关于买桃问题的一点想法

关于MyBatis sqlSession的一点整理

关于java中用itext导出word的一点想法

关于Mybatis的一点小记录