MaBatis 的 Mapper 模板通用书写 分享

    之前在 SSM 框架整合的思想(一) 一文中提到,mapper层的任务应该是:只做最基本的、通用性最强的事情的,它不应该有太多的逻辑上的成分存在。mapper层是直接操作数据库的,它应该在很大程度上只有那四个方法(增改查删),只有特殊情况才应该需要写新的sql。

    那么到底应该怎么样去写这些方法呢?这里分享一下这些方法的书写方法,就是直接当作模板使用即可。(另外听说有人做了通用mapper的项目,有兴趣的也可以了解一下。文中的模板旨在减轻本身使用MyBatis开发的朋友的负担,同时让代码更加简洁、工整)

    直接看代码:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aa.dao.mapper.AccountMapper">
	<resultMap id="resultMap" type="com.aa.domain.entity.Account">
		<result property="id"    		column="id"/>
		<result property="name"      	column="name"/>
		<result property="loginName"    column="login_name"/>
		<result property="password"    	column="password"/>
		<result property="isDelete"    	column="is_delete"/>
	</resultMap>
	
	<sql id="table_name">
		account
	</sql>
	<sql id="column">
		id, name, login_name, password, is_delete
	</sql>
	<sql id="values">
		#{id}, #{name}, #{loginName}, #{password}, #{isDelete}
	</sql>
	<sql id="set_values">
		id=#{id}, name=#{name}, login_name=#{loginName}, password=#{password},is_delete=#{isDelete}	
    </sql>
	<sql id="condition">
		<if test="id != null">
			AND id IN
			<foreach collection="id" item="item" open="(" separator="," close=")">
				#{item}
			</foreach>
		</if>
		<if test="name != null">
			AND name like concat("%/", #{name}, "%") escape "/"
		</if>
		<if test="nameMatch != null">
			AND name = #{nameMatch}
		</if>
		<if test="loginName != null">
			AND login_name = #{loginName}
		</if>
		<if test="isDelete != null">
			AND is_delete = #{isDelete}
		</if>
		
		ORDER BY name
		<if test="start != null and size != null">
			limit ${start},${size}
		</if>
	</sql>
     
	<insert id="add">
		INSERT INTO <include refid="table_name"/>
		(
			<include refid="column"/>
		)VALUES(
			<include refid="values"/>
		)
	</insert>
	
	<update id="update">
		UPDATE <include refid="table_name"/>
		SET <include refid="set_values"/>
		WHERE id = #{id}
	</update>
	
	<select id="query" resultMap="resultMap">
		SELECT <include refid="column"/>
		FROM <include refid="table_name"/>
		WHERE 1=1 <include refid="condition"/>
	</select>
	
	<update id="delete">
		UPDATE <include refid="table_name"/>
		SET is_delete = 0;
		WHERE id IN
			<foreach collection="list" item="item" open="(" separator="," close=")">
				#{item}
			</foreach>
	</update>

</mapper>

这几个方法几乎涵盖所有常用功能:

id="cloumn" 的 sql 中直接列出数据库的全部字段

id="values" 的 sql 中则列出实体的全部字段,与上面的数据库字段位置一一对应

id="set_values" 的 sql 则把所有可能需要更新的字段都写上即可(一般都是把全部字段都写上)

id="condition" 的 sql 是需要的查询条件,具体请看代码(其中的模糊查询已经做了字符转义)

查询方法接口定义使用Map传递参数:

List<Account> query(Map<String, Object> map);

    单单看上面的说明,估计还看不出来怎么个通过用法,这里说明一下。

    首先,新增的肯定没问题的了(我这里使用了UUID,所以需要传递id过来),其次更新,有个问题:如果有些参数没有传值过来,但是那个数据本身已经有值。这时候直接调用更新方法是会清空原来的值的,这种情况必须处理。

    有的人直接在 id="set_values" 的 sql 中写上判断,只有传值的时候才设值。这样就大大增加了代码量了,而且很多都是重复的无用代码,不仅浪费时间,而且后期维护看起来很不方便。

    这个问题只需要在dao层的更新方法封装一层即可:1、先根据传递过来的数据的id查询数据,没有数据,退出;2、有数据,则根据判断字段是否有传值,有则设值。这样的更新方法就不用担心清空数据的问题了,如果是假删除的话,发现我那里写的那个删除方法都是多余的了,这个更新方法就可以解决问题。

    这个封装有个问题,就是:有时候可能我就是要清掉没传值的数据的,那么在dao层再写一个方法,直接调用更新方法即可。

    接着看查询方法:例如:根据id获取数据的,dao层封装一下query方法,把一个id放进一个list里面传递过去。所有形式的查询都只是对这个方法的封装,而不是每种不一样的查询方法都在xml中写一个,这样xml中的代码就能尽可能的减少,更容易维护。

    这时候发现dao层有事可做了,不再是简单调用一下mapper层的方法了,而且做的也只是对mapper层的简单封装,增加通用性,也建议不要涉及任何业务逻辑,这样它的通用性才能得到保障。

    最后,service层就可以尽情的写逻辑实现了,xml代码的减少,就像丢掉了一个大包袱,既获得MyBais的灵活性,也使得代码简洁、工整,拓展性也得到提高。这时候产品跑过老跟你说要增加3个字段的时候,你只需要一下几步操作:增加数据库字段、增加实体字段、在xml中的三个sql中加上字段的罗列。一切解决。resultMap也要配置一下,如果直接返回实体类的话则不需要了。但是建议使用resultMap会更好。

转载于:https://my.oschina.net/watsonos/blog/1514260

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值