1. 程式人生 > >三十二、MyBatis註解SQL

三十二、MyBatis註解SQL

指令碼sql

XML配置方式的動態SQL我就不講了,有興趣可以自己瞭解,下面是用<script>的方式把它照搬過來,用註解來實現。適用於xml配置轉換到註解配置很明顯,在java中寫xml可讀性和維護性太差,尤其當SQL很長時,這樣寫是很痛苦的。

//查詢所有,@Results欄位裡只需對映實體類和表字段名不一致的欄位名
 @Select(" SELECT * FROM child_channel ORDER BY rank ASC,online_status DESC")
    @Results({
            @Result(property = "onlineStatus", column = "online_status"),
            @Result(property = "hasNew", column = "has_new"),
            @Result(property = "updateTm",column = "update_tm"),
            @Result(property = "createTm",column = "create_tm")
    })
 List<Channel> findChannelList();
//用函式
@Select("<script>" +
            " SELECT COUNT(*) FROM child_unit WHERE 1=1 " +
            "  <when test='params.category != null'> AND category = #{params.category} </when> " +
            "  <when test='params.onlineStatus != null'> AND online_status = #{params.onlineStatus} </when> " +
            "  ORDER BY id ASC" +
            "</script>")
    Integer count(@Param(value = "params") Map<String, Object> params);
//連線查
@Select(" SELECT * FROM child_unit c1 JOIN child_unit_position c2 ON c2.unit_id = c1.id WHERE c2.unit_group_id = #{unitGroupId} ORDER BY c2.rank ASC")
    @Results({
            @Result(property = "subTitle", column = "sub_title"),
            @Result(property = "contentId", column = "content_id"),
            @Result(property = "openType", column = "open_type"),
            @Result(property = "onlineStatus",column = "online_status"),
            @Result(property = "hasNew",column = "has_new"),
            @Result(property = "createTm", column = "create_tm"),
            @Result(property = "updateTm", column = "update_tm")
    })
//刪除
@Delete("<script>"
            + " DELETE FROM child_channel WHERE id IN "
            + "     <foreach item='item' index='index' collection='idSet' open='('            separator=',' close=')'>"
            + "         #{item}"
            + "     </foreach>"
            + "</script>")
int deleteByPrimaryKeySet(@Param("idSet") Set<Long> idSet);

在方法中構建sql

dao介面中是不能寫實現的,所以這裡借用內部類來生成動態SQL。增改刪也有對應的@InsertProvider、@UpdateProvider、@DeleteProvider

@Mapper
public interface MybatisDao {
    //使用UserDaoProvider類的findUserById方法來生成sql
    @SelectProvider(type = UserDaoProvider.class, method = "findUserById")
    public List<User> findUserById(User user);
    
    class UserDaoProvider {
        public String findUserById(User user) {
            String sql = "SELECT * FROM user";
            if(user.getId()!=null){
                sql += " where id = #{id}";
            }
            return sql;
        }
    }

這比<script>更加清晰,適用於查詢語句不是很長、條件不多的場景,SQL很直觀。但是在寫很長的SQL時,這樣拼接SQL同樣會很痛苦

結構化SQL

public String findUserById(User user) {    
            return new SQL(){{    
                SELECT("id,name");    
                SELECT("other");    
                FROM("user");    
                if(user.getId()!=null){    
                    WHERE("id = #{id}");    
                }    
                if(user.getName()!=null){    
                    WHERE("name = #{name}");    
                }    
            //從這個toString可以看出,其內部使用高效的StringBuilder實現SQL拼接    
            }}.toString();    
        }    

這是把前面的內部類改造一下

SELECT:表示要查詢的欄位,如果一行寫不完,可以在第二行再寫一個SELECT,這兩個SELECT會智慧的進行合併而不會重複

FROM和WHERE:跟SELECT一樣,可以寫多個引數,也可以在多行重複使用,最終會智慧合併而不會報錯

這樣語句適用於寫很長的SQL時,能夠保證SQL結構清楚。便於維護,可讀性高。但是這種自動生成的SQL和HIBERNATE一樣,在實現一些複雜語句的SQL時會束手無策。所以需要根據現實場景,來考慮使用哪一種動態SQL

上面的例子只是最基本的用法:更多詳細用法,可以參考mybatis中文網的專門介紹

http://www.mybatis.org/mybatis-3/zh/statement-builders.html

List傳值錯誤

動態SQL中,有時要對批量資料進行處理,難免會使用list做為引數

@SelectProvider(type = UserDaoProvider.class, method = "find")
    public List<Map> find(List list);    
    
    class UserDaoProvider {
        public String find(List list) {

這是一個最簡單的list傳參,但是在執行時會報傳參錯誤。這是mybatis內部機制造成的,其引數需要是key/value結構,當遇到這裡不是key/value結構的list時,mybatis會自己把它轉換成key/value結構,key就是他的名字"list",value就是他的值List,要正確傳參需要使用key/value結構的map,如下

@SelectProvider(type = UserDaoProvider.class, method = "find")
    public List<Map> find(List list);    
    
    class UserDaoProvider {
        public String find(Map map) {
            List list = (List) map.get("list");