实现动态SQL的四种方式:
1、XML配置
使用XML配置动态SQL,细节不表,详参:《MyBatis快速上手与知识点总结》 - 5.4 多条件查询 - 动态查询
2、脚本SQL
- 使用注解实现,将XML文件的内容转换为注释即可
- 当然,这种方式可读性差,且难以维护
| @Select("<script>select * from user <if test=\"id !=null \">where id = #{id} </if></script>") |
| public List<User> findUserById(User user); |
3、在方法中构建SQL
- Dao层接口不写实现,次数使用内部类来生成动态SQL,并传入 @SelectProvider 注释
- 增改删也有对应的 @InsertProvider、@UpdateProvider、@DeleteProvider 注释
- 相比于脚本SQL更加清晰,比较直观,但是如果SQL过长的话,拼接会非常麻烦
| @Mapper |
| public interface MybatisDao { |
| |
| @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; |
| } |
| } |
| } |
4、结构化SQL
- 这是把前面的内部类改造一下:
- SELECT:表示要查询的字段,如果一行写不完,可以在第二行再写一个SELECT,这两个SELECT会智能的进行合并而不会重复
- FROM 和 WHERE:跟SELECT一样,可以写多个参数,也可以在多行重复使用,最终会智能合并而不会报错。
- 这样语句适用于写很长的SQL时,能够保证SQL结构清楚。便于维护,可读性高。
- 但是这种自动生成的SQL和HIBERNATE一样,在实现一些复杂语句的SQL时会束手无策。所以需要根据现实场景,来考虑使用哪一种动态SQL
- 上面的例子只是最基本的用法:更多详细用法,可以参考mybatis中文网的专门介绍:
http://www.mybatis.org/mybatis-3/zh/statement-builders.html
| @Mapper |
| public interface MybatisDao { |
| |
| @SelectProvider(type = UserDaoProvider.class, method = "findUserById") |
| public List<User> findUserById(User user); |
| |
| 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(); |
| } |
| } |
关于动态SQL的List传值错误问题
动态SQL中,有时要对批量数据进行处理,难免会使用list做为参数
1、错误代码
- 这是一个最简单的list传参,但是在运行时会报传参错误。
- 这是mybatis内部机制造成的,其参数需要是key/value结构,当遇到这里不是 key/value结构的list时,mybatis会自己把它转换成key/value结构,key就是他的名字"list",value就是他的值 list 对象
| @SelectProvider(type = UserDaoProvider.class, method = "find") |
| public List<Map> find(List list); |
| |
| class UserDaoProvider { |
| public String find(List list) { |
| } |
| } |
2、解决错误
要正确传参需要使用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"); |
| } |
| } |