古老的榕树

MyBatis 自定义通用 Mapper

潘军杰 发表于 2017-04-08 18:08 阅读(9673) 评论(2) 赞(5)
Mybatis 提供自动生成 Mapper 的工具,看看生成的 Mapper,不是尽如人意,比如多表关联和返回的数据类型和传入参类型上。一直想写一个通用的 Mapper,传参类型是 Map,返回 Map 类型;大体分两种数据库操作 DDL 和 DML 操作,而且 DML 分别提供获取一条记录和多条,插入一条记录,批量插入记录,更新,删除一条记录。其中 DDL 是参考了前人的做法,出处不明,知道的跟我说一下。好了,看了一遍 Mybatis 的文档,花时间终于出了初稿。

Mybatis 版本为 3.4.2,环境 Spring boot。

代码分 XML 和 Java 部分:

注:专门操作表结构的,如建表,删表,修改表结构... 
DDLMapper.java
DDLMapper.xml

注:专门操作(查询,插入,修改,删除)表的记录...
DMLMapper.java
DMLMapper.xml


好了程序员喜欢用代码表达

DDLMapper.java 代码:


package cn.banggu.abc.api.mapper.extend;

import org.apache.ibatis.annotations.Param;

/**
 * @author Jack
 * 
 *         执行DDL数据库操作的 Mapper
 */
public interface DDLMapper {
    /**
     * 修改数据库的表名字
     * 
     * @param originalTableName
     * @param newTableName
     * @return
     */
    int alterTableName(@Param("oldTableName") String originalTableName, @Param("newTableName") String newTableName);

    /**
     * truncate指定数据库表的数据
     * 
     * @param tableName
     * @return
     */
    int truncateTable(@Param("tableName") String tableName);

    /**
     * 根据传入的表明,创建新表并且将原表的数据插入到新表中
     * 
     * @param newTableName
     * @param originalTableName
     */
    void createTableAndData(@Param("newTableName") String newTableName,
	    @Param("oldTableName") String originalTableName);

    /**
     * 统计某张表中的总数据条数。
     * 
     * @param tableName
     * @return 指定表中的总记录条数。
     */
    int getRecordCount(@Param("tableName") String tableName);

    /**
     * 获得当前数据库的名字
     * 
     * @return
     */
    String getDBName();

    /**
     * 从指定数据库中,查询是否存在某张表
     * 
     * @param dataBaseName
     * @param tableName
     * @return
     */
    String isTableInDB(@Param("dbName") String dbName, @Param("tableName") String tableName);
}



DDLMapper.xml 代码:


<?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="cn.banggu.abc.api.mapper.extend.DDLMapper">

    <update id="alterTableName">
        alter table ${oldTableName} rename ${newTableName}
    </update>

    <update id="truncateTable">
        truncate table ${tableName}
    </update>
    
    <update id="createTableAndData">
        create table ${newTableName} as select * from ${oldTableName}
    </update>
    
    <select id="getRecordCount" resultType="int">
        select count(1) from ${tableName}
    </select>
    
    <select id="getDBName" resultType="string">
        select database();
    </select>
    
    <select id="isTableInDB" resultType="string">
        SELECT table_name FROM information_schema.tables WHERE table_schema = #{dbName} and TABLE_NAME = #{tableName}
    </select>

</mapper>



DMLMapper.java 代码:


package cn.banggu.abc.api.mapper.extend;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Param;

public interface DMLMapper {

    /**
     * 获取单条数据,封装成 map
     * 
     * @param params
     * @return
     */
    Map<String, Object> query(Map<String, Object> params);

    /**
     * 获取多条记录,封装成 map list
     * 
     * @param params
     * @return
     */
    List<Map<String, Object>> queryList(Map<String, Object> params);

    /**
     * 插入一条记录
     * 
     * @param params
     * @return
     */
    int insert(Map<String, Object> params);

    /**
     * 批量更新数据
     * 
     * 
     * @param table
     * @param params
     *            有序 map 列表
     * @return
     */
    int insertBatch(@Param(value = "table") String table,
	    @Param(value = "params") List<LinkedHashMap<String, Object>> params);

    /**
     * 更新数据
     * 
     * @param params
     * @return
     */
    int update(Map<String, Object> params);

    /**
     * 删除记录
     * 
     * @param params
     * @return
     */
    int delete(Map<String, Object> params);
}



DMLMapper.xml 代码:


<?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="cn.banggu.abc.api.mapper.extend.DMLMapper">

	<select id="query" parameterType="map" resultType="map"> 
		${sql} 
	</select>
	
	<select id="queryList" parameterType="map" resultType="map"> 
		${sql} 
	</select>
	
	<insert id="insert" parameterType="map" useGeneratedKeys="true" keyProperty="id"> 
		<selectKey keyProperty="id" order="AFTER" resultType="int">
	      SELECT LAST_INSERT_ID()
	    </selectKey>
        ${sql}
    </insert>  
    
    <insert id="insertBatch" parameterType="map"> 
    	<if test="table!=null and params!=null">
	         insert into ${table} 
	         <foreach collection="params" item="mp" separator="," index="idx">
	         	<if test="idx==0">
	         		<foreach collection="mp.keys" item="key" open="(" separator="," close=")">    
	            		${key}  
	            	</foreach>  
	         	</if>
	         </foreach>  
	         values
	         <foreach collection="params" item="mp" separator=",">
	         	<foreach collection="mp.keys" item="key" open="(" separator="," close=")">    
	            	#{mp[${key}]}  
	            </foreach>  
	         </foreach>  
         </if>
    </insert>    
	
	<update id="update" parameterType="map" statementType="PREPARED">
		${sql}
	</update>
	
    <delete id="delete" parameterType="map">
        ${sql}
    </delete>

</mapper>



使用方法:DML 的使用,需要参考 xml 的规则,每个方法都是传入 map 参数,除了批量插入方法,其他方法需要传入名为 sql 的参数,就是 sql 语句,举个简单的用法,获取一条 id 为 记录,传入的参数应为:

map["sql"] ="select id,name,sex from table_name where id=#{id}"

map["id"]=3

dmlMapper.query(map);


具体用法还需要看看 xml 的写法。注意 sql 的参数 需要 遵守 mybatis 的写法 #{name}


批量插入比较特殊,和其他用法是有区别的,例如:

List<LinkedHashMap<String, Object>> list = new ArrayList<LinkedHashMap<String, Object>>()

map2["name"]="name2"

map2["sex"]=2


map3["name"]="name3"

map3["sex"]=3

map4["name"]="name4"

map4["sex"]=4

list.add(map2)
list.add(map3)

list.add(map4)


dmlMapper.insertBatch("table_name", list);


参数需要传入 表名和有序 map 列表。


这个通用 Mapper 有什么好处呢?其实只有使用的时候,才能体会出来。你可以不用依赖实体类,不需要写太多的实体类,就可以操作数据,返回 map 类型的数据,方便输出干净的 json,等等。这里不一一列举了。


缺点也说说,因为为了方便,直接都是 传入 map,返回 map,这个做法,行业是不推崇的,但不是绝对,根据具体情况来;另外 xml 使用到了 ${} ,有人说容易 SQL 注入,其实在 service 层,要控制参数,不开放出去,自己要把控好,按需写业务 SQL,不要让 controller 或终端传入 xml 参数 。

(完)

标签: Mybatis 数据库
2 条网友评论

1 楼: 达摩 发表于 2018-02-02 12:00:41   回复 TA

代码格式化一下吧,看着累!

2 楼: 老钱 发表于 2018-08-04 12:05:51   回复 TA

实现不优雅,Mybatis 不是有自动生成代码吗?为何不用?
称呼*
邮箱*
内容*
验证码*
验证码 看不清换张