脚本SQL
xml配置方式见mybatis讲解,下面是用<script>的方式把它照搬过来,用注解来实现。适于xml配置转换到注解配置
@Select("<script>select * from cat <if test="id != null "> where id = #{id} </if></script>")
List<Cat> fintCatById(Cat param);
很明显,在java中写xml可读性和维护性太差,尤其 当sql很长时,这样写是很痛苦的。
在方法中构建SQL
dao接口中是不能写实现的,所以这里借用内部类来生成动态sql。增删改也有对应的@InsertProvider、@UpdateProvider、@DeleteProvider
//使用CatDaoProvider类中的findCatById方法 来生成sql @SelectProvider(type=CatDaoProvider.class,method = "findCatById") List<Cat> findCatById(Cat cat); class CatDaoProvider{ public String findCatById(Cat cat){ String sql = "select * from Cat"; if(cat.getId() != null){ sql += " where id = #{id} "; } return sql; } }
这种方法比<script>更加清晰,适用于查询语句不是很长、条件不多的场景,sql很直观。但是在写很长的sql时,这样拼接sql同样很痛苦。
结构化SQL
class CatDaoProvider{ public String findUserById(Cat cat) { return new SQL(){{ SELECT("id,cat_name,cat_age"); FROM("cat"); if(cat.getId() != null){ WHERE("id = #{id}"); } if(cat.getCatName() != null){ WHERE("cat_name != #{catName}"); } }}.toString();//内部使用高效的StringBuilder实现sql拼接 } }
把前面的内部类改造一下
SELECT:表示 要查询的字段,如果一行写不完,可以在第二行再写一个SELECT,这两个SELECT 会只能的进行合并而不会重复。
FROM和WHERE:跟SELECT一样,可以写多个参数,也可以在多行重复使用,最终会智能合并而不会报错
这样的语句很适合写很长的sql,能够保证代码结构清楚,便于维护,可读性高。但是这种自动生成的sql和hibernate一样,在实现一些复杂语句的sql时会束手无策。
List传值错误
动态sql中,有时要对批量数据进行处理,难免会使用list作为参数
@SelectProvider(type=CatDaoProvider.class,method = "find") List<Map> find(List list);
传递list参数时,在运行时会报传参错误,这是mybatis内部机制造成的,其参数需要是key/value结构,当遇到这里不是Key/value结构的list时,mybatis会自动把它转换成key、value结构,key就是他的名字"list" ,value就是他的值 list,要正确传参需要使用key/value结构的map:
@SelectProvider(type=CatDaoProvider.class,method = "find") List<Map> find(List list); class CatDaoProvider{ public String find(Map map) { List list = (List) map.get("list");