拒絕一次性買賣:MyBatis的mapper和repository可重複生成工具

背景

MyBatis的歷史可謂久遠了,碼農們也在用着各式各樣的代碼生成工具。然而這些工具大部分都有一個缺點,那就是隻能一次性生成文件。若是咱們期間在生成的文件裏作了修改,再次生成時,不少工具會覆蓋咱們的修改。git

爲何會在生成文件後進行修改呢? 由於工具只會幫咱們生成通用的數據庫訪問方法(好比只生成基本的CURD操做),咱們不可避免的要根據實際的業務須要,添加其餘的操做方法。github

同時,數據庫也不是設計完以後就一成不變的了,咱們也可能在開發的過程當中,調整已經建好的表結構。這個時候問題就來了,利用工具再生成一次?那就要人肉合併修改;手動添加更改後的字段進去? 太多了怕遺漏。sql

因此,咱們須要找到一個方法,解決這個痛點。數據庫

原理

熟悉.NET的同窗可能知道,大名鼎鼎Visual Studio也會幫開發人員生成不少代碼,好比asp.net中的aspx的後臺代碼,它是如何保證被工具所生成的代碼片斷和開發人員本身寫的代碼片斷不衝突的呢?它實際上用到了C#的分部類(partial)特性。mybatis

簡單來講,分部類,就是把一個類的代碼,放到多個文件中去寫,C#編譯器負責把他們編譯到一個類中。有了這個特性,代碼生成器就只專一他負責的partial文件就能夠了,開發人員的代碼寫到另一個partial文件中,當年用partial + T4,寫了不少代碼生成模板,屢試不爽。app

但咱們的JAVA不支持這個神器啊(這裏說句題外話,幾年前我從C#轉到JAVA的時候,就感受C#在語言層面比JAVA好太多了,如今好幾年沒碰C#了,不知道它又先進到什麼程度了),怎麼辦呢?asp.net

只有用不是辦法的辦法了,那就是繼承。實體類、Repository接口,用繼承的方式,把工具生成的代碼和預留給開發人員人肉的代碼,分割到兩個文件中。工具

但mapper.xml怎麼辦?這個MyBatis幫咱們想好了(贊一個),利用namespace便可作到。只要namespace指向同一個Repository接口,不管是不是在同一個xml文件裏,MyBatis均可以正確找到。ui

例如咱們有一個Repository是這麼定義的:spa

public interface UserRepository{
    //aaa
    User selectByPrimaryKey(@Param("id") Long id);

    User selectByAccount(@Param("account") String account);
}

那麼如下的兩個mapper.xml結合起來是徹底可用的

UserMapper1.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="com.abc.demo.repository.UserRepository">
    <sql id="TableName">
        jm_user
    </sql>
   <!--asdfdsfsdf-->
    <sql id="BaseColumnList">
     `id`, `account`, `email`, `is_active`
    </sql>

    <resultMap id="BaseResultMap" type="com.abc.demo.entity.User" autoMapping="false">
        <result column="id" property="id" jdbcType="BIGINT"/>
        <result column="account" property="account" jdbcType="VARCHAR"/>
        <result column="email" property="email" jdbcType="VARCHAR"/>
        <result column="is_active" property="isActive" jdbcType="BIT"/>
    </resultMap>
    <select id="selectByPrimaryKey" resultMap="BaseResultMap">
        select
        <include refid="BaseColumnList"/>
        from
        <include refid="TableName"/>
        where
            `id` = #{id}
    </select>
</mapper>

UserMapper2.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="com.abc.demo.repository.UserRepository">
    <select id="selectByAccount" resultMap="BaseResultMap">
        select
        <include refid="BaseColumnList"/>
        from
        <include refid="TableName"/>
        where
            `account` = #{account}
    </select>
</mapper>

你看,UserMapper2.xml中只定義了selectByAccount方法,BaseColumnList、TableName、BaseResultMap都沒有從新定義,能夠直接用UserMapper1.xml的。

jasmine —— 基於數據庫模型和velocity模板的代碼生成工具

利用以上原理,我寫了一個代碼生成工具,讀取數據庫模型,並基於velocity模板,生成代碼。
能夠命令行形式運行,也能夠做爲IDEA的插件運行。

項目地址:https://github.com/kongxiangxin/jasmine
工具下載地址:https://github.com/kongxiangxin/jasmine/releases

源碼裏提供了一個示例DEMO,裏面包含了MyBatis的代碼生成模板,支持以下特性:

  1. 一鍵生成實體類、MyBatis Repository、MyBatis Mapper
  2. 實體類、MyBatis Repository和MyBatis Mapper均利用繼承策略,劃分出XXXX和XXXXBase兩個文件,其中XXXX若是文件存在則不覆蓋,XXXXBase每次生成都會覆蓋。若是在生成後你須要作一些代碼上的調整,請在XXXX文件中修改,而不要在XXXXBase中修改。這樣作的好處是一旦咱們的表結構發生變化須要從新生成時,不會覆蓋您手動改過的代碼。
  3. 若是表存在is_deleted字段,生成的delete方法是邏輯刪除而不是物理刪除。
  4. 若是表存在record_version字段,update語句帶有樂觀鎖,即update .... set record_version=record_version + 1 where .... and record_version=#{record_version}
  5. 若是表存在create_time,insert語句這一列的值是now()
  6. 若是表存在update_time, insert和update語句這一列的值是now()

Quick Start

  1. 去releases頁面,下載最新的jasmine-[version].zip,解壓。
  2. clone源碼至本地,根據實際狀況,修改demo/jasmine.properties中jdbc相關的配置(主要是數據庫鏈接配置)
  3. 執行如下命令:
/path/to/jasmine-[version]/bin/jasmine /path/to/jasmine-src/demo/jasmine.properties

若是一切正常,會在demo下看到生成出來的文件

相關文章
相關標籤/搜索