Spring Boot MyBatis升级篇-注解-动态SQL(if test)-方案二:@Provider(8)
1)动态语言注解
(2)@Provider使用思路
(3)@SelectProvider小试牛刀
(4)@SelectProvider初露锋芒
(5)@SelectProvider过关斩将
(6)@InsertProvider小弟不敢当
(7)@UpdateProvider你加我来改
(8)@DeleteProvider不高兴就删
接下来看下具体的内容:
(1)动态语言注解
对于创建动态的查的语言。MyBatis提供了多个注解如:@InsertProvider,@UpdateProvider,@DeleteProvider和@SelectProvider,这些都是建立动态语言和让MyBatis执行这些语言。
(2)@Provider使用思路
对于MyBatis提供的几个@Provider,里面最主要的参数是type,也就是sql类的Calss对象,另外就是对应的方法名,我们看SelectProvider的源代码:
Java代码 收藏代码 @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface SelectProvider { Class<?> type(); String method(); }
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface SelectProvider { Class<?> type(); String method(); }
所以要实现动态的SQL查询,那么大体的思路就是,编写一个SqlProvider,比如:DemoSqlProvider,在此方法中返回一条SQL语句即可。然后在Mapper类中使用@SelectProvider注解,指定provider类和对应的SQL方法。
接下来我们来解决上一篇博客的问题:
问题:有一个表中有id,name,email等字段,有这么一个查询要求:我们希望的是如果name不为null的话,那么就当做条件,否则就不要当做条件;如果email不为null,那么就当做条件,否则不当做条件。
接下里看看怎么使用@SelectProvider破。
(3)@SelectProvider小试牛刀
我们先编写一个DemoSqlProvider,代码如下:
package com.kfit.demo.mapper; import com.kfit.demo.bean.Demo; public class DemoSqlProvider { /** * 查询语句. * @param demo * @return */ public String select5(Demo demo){ StringBuffer sql = new StringBuffer("select *from demo where 1=1 "); if(demo.getName() != null){ sql.append(" and name=#{name}"); } if(demo.getEmail() != null){ sql.append(" and email=#{email}"); } return sql.toString(); } }
package com.kfit.demo.mapper; import com.kfit.demo.bean.Demo; public class DemoSqlProvider { /** * 查询语句. * @param demo * @return */ public String select5(Demo demo){ StringBuffer sql = new StringBuffer("select *from demo where 1=1 "); if(demo.getName() != null){ sql.append(" and name=#{name}"); } if(demo.getEmail() != null){ sql.append(" and email=#{email}"); } return sql.toString(); } }
在DemoMapper中加入查询方法:
@SelectProvider(type=DemoSqlProvider.class,method="select5") public List<Demo> select5(Demo demo);
@SelectProvider(type=DemoSqlProvider.class,method="select5") public List<Demo> select5(Demo demo);
这里使用@SelectProvider,不是@Select了。
访问1:http://127.0.0.1:8080/select4会返回全部数据,动态SQL是:
SELECT * from Demo WHERE 1=1
- SELECT * from Demo WHERE 1=1
访问2:http://127.0.0.1:8080/select4?name=王五会返回name=王五的数据,动态SQL是:
- SELECT * from Demo WHERE 1=1 and name=?
- SELECT * from Demo WHERE 1=1 and name=?
访问3:http://127.0.0.1:8080/select4?name=王五&email=aa@qq.com会返回name=王五并且email=aa@qq.com的数据,动态SQL是:
- SELECT * from Demo WHERE 1=1 and name=? and email=?
- SELECT * from Demo WHERE 1=1 and name=? and email=?
(4)@SelectProvider初露锋芒
上面的代码直接纯SQL编写了,可读性还是相对差了点,MyBatis提供了SQL类(org.apache.ibatis.jdbc.SQL),可以让代码看起来更有意义。
在DemoSqlProvider中加入方法:
/** * 查询语句.使用SQL * @param demo * @return */ public String select6(final Demo demo){ return new SQL(){{ SELECT("id,name,email"); FROM("demo"); if(demo.getName() != null){ WHERE("name=#{name}"); } if(demo.getEmail() != null){ WHERE("email=#{email}"); } }}.toString(); }
在DempMapper中加入代码:
@SelectProvider(type=DemoSqlProvider.class,method="select6") public List<Demo> select6(Demo demo);
(5)@SelectProvider过关斩将
原以为万事大吉了,开心的不行,于是乎,信手拈来句代码,在查询代码加入:
PageHelper.startPage(1, 2);整个代码如下:
@RequestMapping("/select6") public List<Demo> select6(Demo demo){ PageHelper.startPage(1, 2); return demoService.select6(demo); }
@RequestMapping("/select6") public List<Demo> select6(Demo demo){ PageHelper.startPage(1, 2); return demoService.select6(demo); }
运行,访问:http://127.0.0.1:8080/select6完了,这是什么鬼: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'providerTakesParameterObject' in 'class org.apache.ibatis.builder.annotation.ProviderSqlSource' 出现以上问题,是由于我们使用的PageHelper版本导致的,升级版本即可。
运行,访问:http://127.0.0.1:8080/select6完了,这是什么鬼:
nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'providerTakesParameterObject' in 'class org.apache.ibatis.builder.annotation.ProviderSqlSource'
出现以上问题,是由于我们使用的PageHelper版本导致的,升级版本即可。
原先的版本为:
Xml代码 收藏代码 <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>4.1.0</version> </dependency> [xml] view plain copy
升级为:
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>4.2.1</version> </dependency>
貌似:4.1.5就支持@SelectProvider分页查询了(未进行验证)。
(6)@InsertProvider小弟不敢当
最麻烦的查询搞定了之后,这个就简单了,
在DemoSqlProvider中加入如下代码:
/** * 查询语句.使用SQL * @param demo * @return */ public String save3(final Demo demo){ return new SQL(){{ INSERT_INTO("demo"); //多个写法. INTO_COLUMNS("name","email"); INTO_VALUES("#{name}","#{email}"); //条件写法. // if(demo.getName() != null){ // VALUES("name","#{name}"); // } // if(demo.getEmail() != null){ // VALUES("email","#{email}"); // } }}.toString(); }
在DemoMapper中加入如下代码:
ava代码 收藏代码 @InsertProvider(type=DemoSqlProvider.class,method="save3") @Options(keyProperty="id",keyColumn="id",useGeneratedKeys=true) public void save3(Demo demo);
(7)@UpdateProvider你加我来改
DemoSqlProvider中的代码如下:
Java代码 收藏代码 /** * @param demo * @return */ public String update2(final Demo demo){ return new SQL(){{ UPDATE("demo"); //条件写法. if(demo.getName() != null){ SET("name=#{name}"); } if(demo.getEmail() != null){ SET("email=#{email}"); } WHERE("id=#{id}"); }}.toString(); }
在DemoMapper中的代码:
码 收藏代码 @UpdateProvider(type=DemoSqlProvider.class,method="update2") public int update2(Demo demo);
(8)@DeleteProvider不高兴就删
DemoSqlProvider代码:
Java代码 收藏代码 /** * @param demo * @return */ public String delete2(){ return new SQL(){{ DELETE_FROM("demo"); WHERE("id=#{id}"); }}.toString(); }
在DemoMapper中的代码:
@UpdateProvider(type=DemoSqlProvider.class,method="delete2") public int delete2(int id);