Spring Boot學習筆記----mybatis註解(二)
之前的博文講述了mybatis註解的簡單用法,包括@Select,@Insert,@Update,@Delete,@Result,@Param和@Options。本文將記錄多個Provider的用法。
如何理解Provider呢?只是換了一種形式。將原來的SQL註解繫結放到了一個類裡,再將該類註解繫結至原有位置。
先對比看一下形式吧。
原有SQL註解繫結
@Insert("Insert into hero(name,age) values(#{sName},#{nAge})")
@Options(useGeneratedKeys=true, keyColumn="id" , keyProperty="id")
void addHero(Hero hero);
使用provider後的形式
@InsertProvider(type=HeroProvider.class,method = "addHero")
void addHero(Hero hero);
即,HeroProvider類中的addHero方法所返回的SQL語句,跟@Insert所繫結的SQL語句一致。
我們注意到插入provider的繫結是使用了@InsertProvider註解。
類似的註解,閉著眼也能想到。@SelectProvider,@UpdateProvider,@DeleteProvider,對應的功能,不用閉眼也能想到。
接下來,我們看看HeroProvider的實現。
package com.breakloop.mybatis.provider;
import com.breakloop.mybatis.entity.Hero;
import org.apache.ibatis.jdbc.SQL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HeroProvider {
Logger logger= LoggerFactory.getLogger(HeroProvider.class);
public String addHero(Hero hero){
String sqlStr;
SQL sql= new SQL();
sql.INSERT_INTO("hero");
if(hero.getAge()>0 && hero.getName()!=null){
sql.VALUES("name","'"+hero.getName()+"'");
sql.VALUES("age", String.valueOf(hero.getAge()));
}
sqlStr=sql.toString();
logger.info("sql="+sqlStr);
return sqlStr;
}
}
這裡需要注意的是,SQL的VALUES方法的傳參都是String型別。如果某一欄位為String型別,則需要給欄位資料加單引號!否則,欄位資料將會被識別為欄位名稱,導致SQL語句異常。
再來為HeroProvider 新增選擇方法。看看@SelectProvider註解的使用。
public String selectByAge(int age){
String sqlStr;
SQL sql= new SQL();
sql.SELECT("*");
sql.FROM("hero");
sql.WHERE("age="+age);
sqlStr = sql.toString();
logger.info("sql="+sqlStr);
return sqlStr;
}
同時,在Mapper中進行繫結。
@SelectProvider(type = HeroProvider.class,method = "selectByAge")
List<Hero> selectByAge(int age);
從面兒上看,沒什麼問題。但執行時報錯。
Error invoking SqlProvider method (com.breakloop.mybatis.provider.HeroProvider.selectByAge). Cannot invoke a method that holds named argument(@Param) using a specifying parameterObject. In this case, please specify a 'java.util.Map' object.]
這種情況出現在傳參不是實體類或者java.util.Map時。
解決方案有兩種
(1)使用@Param對引數進行繫結,即
@SelectProvider(type = HeroProvider.class,method = "selectByAge")
List<Hero> selectByAge(@Param("aa") int age);
public String selectByAge(@Param("aa") int age){
String sqlStr;
SQL sql= new SQL();
sql.SELECT("*");
sql.FROM("hero");
sql.WHERE("age=#{aa}");
//或者
//sql.WHERE("age="+age);
sqlStr = sql.toString();
logger.info("sql="+sqlStr);
return sqlStr;
}
(2)使用Map傳參
@SelectProvider(type = HeroProvider.class,method = "selectByAge")
List<Hero> selectByAge(Map<String, Integer> params);
public String selectByAge(Map<String,Integer> params){
String sqlStr;
SQL sql= new SQL();
sql.SELECT("*");
sql.FROM("hero");
sql.WHERE("age="+params.get("age"));
sqlStr = sql.toString();
logger.info("sql="+sqlStr);
return sqlStr;
}
照葫蘆畫瓢,@UpdateProvider和@DeleteProvider也就沒什麼了。這裡我們給出程式碼示例。
@UpdateProvider(type = HeroProvider.class,method = "updateHero")
void updateHero(Hero hero);
@DeleteProvider(type = HeroProvider.class,method = "deleteHero")
void deleteHeroByName(@Param("aa") String name,@Param("bb") int age);
public String updateHero(Hero hero){
String sql= new SQL(){
{
UPDATE("hero");
if(hero.getAge()>0 && hero.getName()!=null){
SET("name='"+hero.getName()+"'");
SET("age="+hero.getAge());
WHERE("id="+hero.getId());
}
}
}.toString();
logger.info("sql="+sql);
return sql;
}
public String deleteHero(@Param("aa") String sName, @Param("bb") int nAge){
String sql= new SQL(){
{
DELETE_FROM("hero");
if(nAge>0){
WHERE("age="+nAge);
}
if(sName!=null){
WHERE("name='"+sName+"'");
}
}
}.toString();
logger.info("sql="+sql);
return sql;
}
至此,註解方式的動態SQL方法小結完畢。
感覺mybatis的水很深。很多點都要深看,短時間內只能瞭解如何使用。至於為什麼,怎麼個原理,需要再挖。當然,JPA的存在,使得選擇方式變多,深挖也變猶豫。呵呵~