本文首發我的公衆號《andyqian》,期待你的關注!程序員
這篇文章很是簡單,沒有什麼高深技術。這些細節用過Mybatis的童鞋都知道。寫這篇文章的原因是:在最近的工做中,接手了一個外包項目,發現項目中 mapper 文件所有是自動生成的,代碼十分冗餘且不易維護,用知乎上的回答,這算得上是名副其實的」屎山」代碼了。如今用 Mybatis作持久層算是Java系的主流,其中有一個主要的緣由就是靈活性,但經過代碼生成工具偏偏打破它的靈活性,生成一堆冗餘且無用的代碼,方法的命名也十分奇怪,總之,簡直就是災難。前者一時爽,後者嗚呼哀哉,特別是上線後,那就更可怕了,到底改仍是不改呢?不改強迫症,看着就不舒服,一改就要花費成倍的時間,彷彿是生產事故在像你招手。so,本着程序員本是同根生的原則,真心建議你們不要使用生成工具。前期的一點點時間的節省,後期真的就須要成倍的時間。spring
自動生成代碼的若干宗罪:sql
SQL怎麼優化?apache
命名不規範如何修改?數據結構
冗餘代碼怎麼辦?經常是爲了一個代碼,生成一堆代碼。mybatis
參數可理解性?app
…dom
1. 使用 _parameter 關鍵字工具
接口:優化
List<Address> queryAddressBySimplte(String address,String coinType);
XML文件:
<sql id="querySQL"> select oid, party_id, coin_type, address,address_alias,address_type, wallet_id, user_id, status, register_time, created_time, update_time from t_molecule_address </sql> <select id="queryAddressBySimplte" resultType="Address"> <include refid="querySQL"/> where <if test="_parameter!=null and _parameter!=''"> address=#{0} </if> <if test="_parameter!=null and _parameter!=''"> and coin_type=#{1} </if> </select>
其中_parameter 參數表示參數對象,其內部數據結構爲:MapperParamMap 。按照index進行參數值的獲取。
注意事項:
當方法是單個參數時,能夠直接使用 #{_parameter} 進行獲取。
當方法有多個參數時,則不能直接使用 #{_parameter} 方式,必須經過Index的形式進行獲取,#{0} 表示第一個參數,#{1} 表示第二個參數。
當方法爲多個參數時使用 #{_parameter} 時。日誌顯示以下所示:
DEBUG main - ==> Preparing: select oid, party_id, coin_type, address,address_alias,address_type, wallet_id, user_id, status, register_time, created_time, update_time from t_molecule_address where address=? and coin_type=? 2019-05-07 13:24:31 DEBUG main - ==> Parameters: {0=0xbfa8f58ebea6e0643a5370c555a5bacfe320fd72, 1=ETH, param1=0xbfa8f58ebea6e0643a5370c555a5bacfe320fd72, param2=ETH}(MapperParamMap)
優勢:
暫時沒想出來啥優勢。(知道的能夠在評論區留言補充)。
缺點:
多個參數時,只能經過角標的形式引入,可讀性,以及可理解性比較差。
傳參時,不一樣參數數量其規則不一樣,容易出錯。
代碼生成工具使用的比較多,我相信不多有人主動用這種方式。
2. 使用@Param 註解
接口:
List<Address> queryAddressBySimplte(@Param("address")String address,@Param("coinType") String coinType);
XML文件
<sql id="querySQL"> select oid, party_id, coin_type, address,address_alias,address_type, wallet_id, user_id, status, register_time, created_time, update_time from t_molecule_address </sql> <select id="queryAddressBySimplte" resultType="Address"> <include refid="querySQL"/> where <if test="_parameter!=null and _parameter!=''"> address=#{address} </if> <if test="_parameter!=null and _parameter!=''"> and coin_type=#{coinType} </if> </select>
注意事項:
在XML文件中的參數名與@Param()中的參數名一致,與方法參數名無關。
例如:
List<Address> queryAddressBySimplte(@Param("addressAlias")String address,@Param("coinTypeAlias") String coinType);
這時咱們在XML文件中,對應的參數應該爲:
<select id="queryAddressBySimplte" resultType="Address"> <include refid="querySQL"/> where <if test="_parameter!=null and _parameter!=''"> address=#{addressAlias} </if> <if test="_parameter!=null and _parameter!=''"> and coin_type=#{coinTypeAlias} </if> </select>
使用註解時,咱們還能夠 params 方式。
例如:
<select id="queryAddressBySimplte" resultType="Address"> <include refid="querySQL"/> where <if test="param1!=null and param1!=''"> address=#{param1} </if> <if test="param2!=null and param2!=''"> and coin_type=#{param2} </if> </select>
其中 param1 表示第一個參數,param2 表示第二個參數。固然了,不推薦你們這麼用,由於對可讀性以及可理解性都不友好。
優勢:
代碼可讀性好,參數自可讀。
可重命名參數名。
缺點:
須要引入@Param 註解 (固然,我不認爲這是缺點)。
可擴展性較弱。(超過3個參數的方法,就不建議使用該方法了)。
3. 使用 Java 對象
Domain對象(省略Get / Set 方法):
public class Address { /** * 幣種類型 */ private String coinType; /** * 地址 */ private String address; ...
接口:
List<Address> queryAddressBySimplte(Address address);
XML文件:
<select id="queryAddressBySimplte" resultType="Address" parameterType="Address"> <include refid="querySQL"/> where <if test="address!=null and address!=''"> address=#{address} </if> <if test="coinType!=null and coinType!=''"> and coin_type=#{coinType} </if> </select>
其中參數爲 Address 對象中的屬性便可。若是參數爲非對象屬性中的參數,即會顯示如下異常:
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'coinType11' in 'class io.invault.molecule.dal.domain.address.Address'
優勢:
可擴展性好。
參數名與對象列明一致,理解性好。
缺點:
須要另外引入一個Java實體對象。(其實這是與可擴展性矛盾的地方)。
經過上述幾種傳參方式,咱們已經很是清楚每一種方式的應用場景以及優缺點。若是要說最佳的方式,還得迴歸到Java規範上來。在Java手冊中,有這麼一條,建議超過3個參數及以上方法,改用參數對象傳遞。在上述例子中,咱們一樣遵照這樣的規範是極好的。總之,咱們應該明白:代碼是給人讀的,而不是計算機!。
相關閱讀:
《重構不徹底指南!》