大家在写测试小工具平台(java+springboot+mybatis前后台小系统)之时,会苦于mybatis一个一个摆上所需表字段和实体类成员变量的映射关系。正如mybatis官网资料文档所说:“理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。”(https://mybatis.org/mybatis-3/zh/dynamic-sql.html)
就像这样(如下图),密密麻麻,我就问你害不害怕,密集恐惧症的测试开发er估计会崩溃~~~所以要用动态SQL摆脱痛苦!!!
通过注解实现动态sql一共需要四个步骤:1.创建表,2.创建entity类,3.创建mapper类, 4.创建动态sql的Provider类。
1、创建PersonMapper.java(接口):【一般写在dao层】
如下代码, @XXXProvider(type=提供动态SQL的类名.class, method="提供动态SQL的类里面的方法名") ,
@XXXProvider,就是今天我们所讲的@SelectProvider、@InsertProvider、@UpdateProvider注解关键字。
package com.blueStarWei.mappers;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.UpdateProvider;
import com.blueStarWei.entity.TPersonInfo;
public interface PersonMapper {
@SelectProvider(type=PersonDynamicSqlProvider.class, method="select") //说白了,其实@xxxProvider通过写在dao层的type=PersonDynamicSqlProvider.java这个类中的select方法,生成动态SQL
List<TPersonInfo> findByNameAndAge(Map<String,Object> map); //这个传入参数map,其实是通过写在service层传入参数的personMapper.findByNameAndAge(map)传进来的(1、同样也是Map键值类型;2、personMapper是通过@Autowired注解给PersonMapper接口注入进来的)
@InsertProvider(type=PersonDynamicSqlProvider.class, method="insert")
void insert(TPersonInfo person);
@UpdateProvider(type=PersonDynamicSqlProvider.class, method="update")
void update(TPersonInfo person);
}
2、创建类PersonDynamicSqlProvider.java【一般也写在dao层】
package com.blueStarWei.mappers;
import java.util.Map;
import org.apache.ibatis.jdbc.SQL;
import com.blueStarWei.entity.TPersonInfo;
public class PersonDynamicSqlProvider {
public String insert(TPersonInfo person){
return new SQL(){
{
INSERT_INTO("T_PERSON_INFO");
if(person.getName() != null){
VALUES("name", "#{name}");
//VALUES("name", person.getName());
//Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'Java' in 'field list'
}
if(person.getAge() != null){
VALUES("age", "#{age}");
}
}
}.toString();
}
//自测打印结果将会是:(如果person.setName("王刚")和person.setAge(22)都分别赋值了“王刚”和22,都不为空):
/*
INSERT INTO T_PERSON_INFO VALUES(#{name}, #{age})
*/
public String update(TPersonInfo person){
return new SQL(){
{
UPDATE("T_PERSON_INFO");
if(person.getName() != null){
SET("name=#{name}");
}
if(person.getAge() != null){
SET("age=#{age}");
}
if(persion.getId() != null){
WHERE("id=#{id}");
}
}
}.toString();
}
//自测打印结果将会是:(如果person.setName("王刚")和person.setAge(22)都分别赋值了“王刚”和22,person.setId("12345678"),都不为空):
/*
UPDATE T_PERSON_INFO SET name = #{name}
WHERE (id = #{id})
*/
public String select(Map map){
return new SQL(){
{
SELECT("*");
FROM("T_PERSON_INFO");
if(param.get("id")!=null) {
WHERE("id=#{id}");
}
}
}.toString();
}
//如果这里我只测试一下select方法,在主方法中如下操作:
public static void main(String[] args) {
PersonDynamicSqlProvider test = new PersonDynamicSqlProvider();
Map map =new HashMap();
map.put("id","12345678");
System.out.println(test.select(map));
}
/*运行结果:
SELECT * FROM T_PERSON_INFO
WHERE ( id = #{id} )
*/
}
3、以上main方法是供自己测试动态SQL写的正确与否 而用的,但是外层(也就是调用方)怎么用呢?【一般写在service层,写好了供以后的controller层调用】
看见第1点的接口PersonMapper了吗?将通过spring框架中的注解关键字(@Autowired)注入接口(附加说明:@Autowired所在spring包:org.springframework.beans.factory.annotation.Autowired)
package com.xxx.service; //一般写在service层
import org.springframework.beans.factory.annotation.Autowired;
@Autowired
PersonMapper personMapper;
List<TPersonInfo> list = personMapper.findByNameAndAge(map);
personMapper.insert(tPersonInfo);
personMapper.update(tPersonInfo);
剩下的就不多说了,上面的map、tPersonInfo这两个传入的参数,根据自己测试或业务上的需要去传值,就OK了!
综上所述,第3点是传实际的值,进入到第1点接口的两个方法中,然后通过@XXXProvider(type=提供动态SQL的类名.class, method="提供动态SQL的类里面的方法名") ,根据传的这批字段,有哪些不为空的,根据不为空的字段生成mybatis SQL语句,然后将值代入SQL中执行(和传统mybatis一样),这就是动态SQL执行全流程!