Mybatis動態構建Sql(無實體類)

先簡單說下Mybatis的動態sql,這不是今天的重點。web

MyBatis的動態SQL是基於OGNL表達式的,它能夠幫助咱們方便的在SQL語句中實現某些邏輯。
sql

例如,sql語句where條件中,須要一些安全判斷,例如按某一條件查詢時若是傳入的參數是空,此時查詢出的結果極可能是空的,也許咱們須要參數爲空時,是查出所有的信息
安全

MyBatis中用於實現動態SQL的元素主要有:mybatis

  • if架構

  • choose(when,otherwise)app

  • trimide

  • wherespa

  • set架構設計

  • foreach設計

示例mapper.xml:

<select id="findActiveBlogLike"  
    parameterType="BLOG" resultType="BLOG">  
    SELECT * FROM BLOG  
    WHERE  
    <trim prefix="WHERE" prefixOverrides="AND |OR ">  
        <choose>  
            <when test="title != null">  
                AND title like #{title}  
            </when>  
            <when test="author != null and author.name != null">  
                AND title like #{author.name}  
            </when>  
            <otherwise>  
                AND featured = 1  
            </otherwise>  
        </choose>  
    </trim>  
</select>  
  
<update id="updateAuthorIfNecessary"  
    parameterType="Author">  
    update Author  
    <trim prefix="where" prefixOverrides=",">   
    <set>  
        <if test="username != null">username=#{username},</if>  
        <if test="password != null">password=#{password},</if>  
        <if test="email != null">email=#{email}</if>  
    </set>  
    where id=#{id}  
    </trim>  
</update>

可是問題來了,若是咱們沒有實體怎麼辦?如上代碼,都是關聯實體Author,BLOG。

更進一步,若是咱們連字段和表名都是程序運行時產生的,那麼在Mybatis中,咱們的mapper.xml又該如何寫呢?

不要說這種需求不多,實際上不少靈活性和擴展性要求比較高的應用,物理模型不肯定,也便是你的表結構不肯定,甚至連表名字都不肯定,基本上sql中的每個字母都不是寫死的。


我如今就遇到了這種需求,簡單描述以下:

事先定義好了不少數據集的信息模型,針對這些信息模型生成物理模型。而咱們須要針對這些物理模型進行操做。而這些數據集一旦更新,信息模型以及物理模型都要變更,因此事先不可能徹底肯定物理表結構等等信息。此時應該怎麼在mybatis中進行處理呢?

翻閱mybatis文檔,在一個不起眼的地方發現update標籤有一個屬性statementType,根據jdbc的經驗,這應該是控制sql預編譯仍是非預編譯的,若是sql執行是預編譯的,那麼動態傳入字段名,表名之類的,顯然 

是不行的,因此你必須改爲非預編譯的。

二者有什麼區別呢?若是是預編譯的,那麼系統在初始化時就會讀取這段sql代碼,將指定的實體類中的字段替換了相似#{}這樣的語句,就是造成了相似這樣的語句:

"select * from tableName where id=?" 這個時候你在系統運行時再想向這句sql中替換tableName或者id,結果可想而知。若是是非預編譯呢,結果恰好相反,他會在系統運行時纔會去生成這樣相似的語句。此時就能夠去替換這些動態的字段或者表名之類。這樣在結合以前所講的返回類型的設置,咱們的問題就解決了。

咱們能夠不用設定參數和返回類型的實體類,只須要造成一個動態的表名和字段名的列表類。就能夠動態對那些未知的物理模型進行操做.以下代碼可做參考:

<select id="queryMetaList" resultType="Map" statementType="STATEMENT">  
select * from ${tableName} t where  
<foreach item="item" index="index" collection="field" open=" "  
separator="and" close=" ">  
<choose>  
<when test="item.fieldType == 'DATE' and item.dateQueryFlag == 0">  
${item.fieldCode} between  
to_date('${item.fieldValue}','yyyy-mm-dd  
hh24:mi:ss')   
</when>  
<when test="item.fieldType == 'DATE' and item.dateQueryFlag == 1">  
to_date('${item.fieldValue}','yyyy-mm-dd  
hh24:mi:ss')   
</when>  
<when test="item.fieldItemCode != null and item.fieldItemCode != ''">  
${item.fieldCode} =  
'${item.fieldItemCode}'  
</when>  
<otherwise>  
${item.fieldCode} =  
'${item.fieldValue}'  
</otherwise>  
</choose>  
</foreach>  
  
</select>

注:會有sql注入危險,代碼中要處理。

另外,注意返回值,在mybatis中,不管你指定仍是不指定返回類型,mybatis都會默認的先將查詢回的值放入一個hashMap中(若是返回的值不止一條就是一個包含hashMap的list)。這其中的區別在於,若是你指定了返回類型,mybatis將會根據返回類型的實體類來從hashMap中獲取值並set到這個實體類中。若是不指定就默認返回一個HashMap<String,Object>(List<HashMap<String,Object>>)。

咱們沒有實體,固然就不要指定返回值,默認接受處理List<HashMap<String,Object>>結構的返回值便可。

最後發點感慨:

親,不要再把實體寫死了,或者不要有實體。實體寫死,最直接的後果就是:Hibernate會把sql框死,Mybatis也會把sql框死,手寫jdbc放入實體,也同樣是死,有新模塊,你還得從web到dao寫一串,累不累,你還怎麼玩。

因此,作大型平臺級應用的架構設計,儘可能不要停留在一個表對應一個實體的階段,必須考慮應用的動態可擴展和靈活性。

相關文章
相關標籤/搜索