mybatis中Mapper接口注入动态Sql语句 #{ }和${}的区别

1.通过注解@Select

mapper类

// 此处maper注解最好和配置文件中的 mapper-locations: com.wlw.mapper配合使用
@Repository
@Mapper
public interface RecDescribeMapper {

    /* 不加@param注解会报错
     * @param注解必须加上,否则mybatis就会使用默认注解(param1、param2、按顺序...),
     * 这时可以把@select  中的sql语句的#{bf}要改为#{param0},#{ef}要改为#{param1}。
     * 如果不改就会报错:如图1-1所示
     * 所以建议参数都加@Param注解
    @Select({"select  * from RecDescribe where TimeFlag >= #{bF} and TimeFlag <= #{eF}"})
    public List<RecDescribe> selectByTimeFlag(@Param("bF") String bF, @Param("eF") String eF);
}

《mybatis中Mapper接口注入动态Sql语句 #{ }和${}的区别》 图1-1

调用类

/**
 * 查询gp数据类
 * @author Thomas
 */
@Service
public class QueryServiceImpl implements QueryService {

    @Autowired
    RecDescribeMapper recDescribeMapper;

    public List<GPS> queryPeriodData(String moduleName, String bTime, String eTime) {

        String bf = bTime.split(" ")[1].replace("-", "");
        String ef = eTime.split(" ")[1].replace("-", "");
        List<RecDescribe> recs = recDescribeMapper.selectByTimeFlag(bf, ef);
        System.out.println(recs);
    }
}

2通过注解 @SelectProvider

SelectProvider类
多个方法参数时,用Map进行代替,否则会找不到对应的参数并报错


org.apache.ibatis.binding.BindingException: 
Parameter 'arg0' not found. Available parameters are [param5, bTime, param6, eTime, moduleTable, kid, gpsTable, model, param3, param4, param1, param2]
    at org.apache.ibatis.binding.MapperMethod$ParamMap.get(MapperMethod.java:202) ~[mybatis-3.4.2.jar:3.4.2]
    at org.apache.ibatis.builder.annotation.ProviderSqlSource.extractProviderMethodArguments(ProviderSqlSource.java:111) ~[mybatis-3.4.2.jar:3.4.2]
    at org.apache.ibatis.builder.annotation.ProviderSqlSource.createSqlSource(ProviderSqlSource.java:89) ~[mybatis-3.4.2.jar:3.4.2]
    at org.apache.ibatis.builder.annotation.ProviderSqlSource.getBoundSql(ProviderSqlSource.java:73) ~[mybatis-3.4.2.jar:3.4.2]
其中 param0 ~ param5 (有时会出现 arg0 ~ arrg5) 是mybatis的默认参数,对应本例Mapper类中
public List<GPS> queryGpsDataByPeriod(@Param("gpsTable") String gpsTable,
                                          @Param("moduleTable") String moduleTable,
                                          @Param("kid") String kid,
                                          @Param("model")String model,
                                          @Param("bTime")String bTime,
                                          @Param("eTime")String eTime);
方法的参数(按顺序对应)
其他的bTime、eTime等,是因为我加了@Param注解才产生的,如果不加,就没有这些项。
/**
 * 动态生成sql语句
 * 方式1相比于方式2 可以生成动态表名,但是不会进行预编译过程,可能产生sql注入
 * @author Tomas
 * @date 2017/12/13
 */
public class DynamicSqlProvider {

    /**
     * 方式1
     * @param map
     * @return
     */
    public String findGpsPeriodDataBySql1(Map<String, String> map){ 

        /*map中是参数名称和值得key-value对
        * 如果Mapper中加了@Param 注解就可以用参数名作为map的key
        * 时间是无论Mapper接口的方法中加不加@Param注解,都可以用mybatis默认的参数名称(param0 ~ param5)(arg0 ~ arrg5)获取参数值
        */ 

       // 通过参数名称获取对应值
       // String GpsTable = map.get("gpsTable");
       // String moduleTable = map.get("moduleTable");
       // String kid = map.get("kid");
       // String model = map.get("model");
       // String bTime = map.get("bTime").substring(1);
       // String eTime = map.get("eTime").substring(1);

       // 此处用param
        String GpsTable = map.get("param0");
        String moduleTable = map.get("param1");
        String kid = map.get("param2");
        String model = map.get("param3");
        String bTime = map.get("param4").substring(1);
        String eTime = map.get("param5").substring(1);

        // 打印map 可以发现map中已经含有bTime 、param0 ~param5的参数K-V对
        // {param5= 2015-12-02 15:01:42, bTime= 2015-12-02 15:01:42, param6= 2017-12-14 15:01:42, eTime= 2017-12-14 15:01:42, moduleTable=LTM20161124, kid=f01f35d5-24b1-48ad-9246-9c3b7267184b, gpsTable=GPS20161124, model=4G, param3=f01f35d5-24b1-48ad-9246-9c3b7267184b, param4=4G, param1=GPS20161124, param2=LTM20161124}
        System.out.println(map.toString());
        return "Select g.*,m.KID,m.LAC,m.CI,m.GpsTime,'"+ model +"' Model" +
                " from "+ GpsTable +" g left join " + moduleTable +" m " +
                " on g.GpsTime = m.GpsTime where" +
                " m.KID = '"+ kid +"' and m.GpsTime > '"+ bTime +"' and m.GpsTime < '"+ eTime +"'";
    }

    /**
     * 方式2
     * 通过#{key}直接获取map中对应的参数名称,前提是Mapper中加@Param注解
     * 推荐此方式
     * @param map
     * @return
     */
    public String findGpsPeriodDataBySql(Map<String, String> map){
        
        return new SQL(){
            {
                SELECT("g.*,m.KID,m.LAC,m.CI,m.GpsTime,#{model} Model ");
                FROM("GPS20161124 g ");
                INNER_JOIN("MM20161124 m on g.GpsTime = m.GpsTime ");
                WHERE("m.KID = #{kid} and m.GpsTime > #{bTime} and m.GpsTime < #{eTime}");
            }
        }.toString();
    }
}

Mapper类


    /**
     * 不使用@param注解
     * SelectProvider中对应方法的参数 不能 通过名称直接获,只能按参数排序获取 #{param0}
     * @param GpsTable
     * @param moduleTable
     * @param kid
     * @param model
     * @param bTime
     * @param eTime
     * @return
     */
    @SelectProvider(type = DynamicSqlProvider.class,
    method = "findGpsPeriodDataBySql")
    public List<GPS> queryGpsDataByPeriodO(String GpsTable, String moduleTable, String kid, String model, String bTime, String eTime);

    /**
     * 使用字段名
     * SelectProvider中对应方法的参数 可以 通过名称直接获取(对应方式2中的 #{})
     * @param gpsTable
     * @param moduleTable
     * @param kid
     * @param model
     * @param bTime
     * @param eTime
     * @return
     */
    @SelectProvider(type = DynamicSqlProvider.class,
            method = "findGpsPeriodDataBySql")
    public List<GPS> queryGpsDataByPeriod(@Param("gpsTable") String gpsTable,
                                          @Param("moduleTable") String moduleTable,
                                          @Param("kid") String kid,
                                          @Param("model")String model,
                                          @Param("bTime")String bTime,
                                          @Param("eTime")String eTime);

调用类 和 1 中的调用类相似。

3. #和$的区别

#{}
1.#能防止sql注入,$不能
2.$方式一般用于传入数据库对象,例如传入表名.
3.MyBatis排序时使用order by 动态参数时需要注意,用$而不是#
4.#传入值是引用,而$是其本身:
   id = 1, select #{id} from tablename -> select 1  from tablename(引用)
   id = 1, select ${id} from tablename -> select id from tablename
    原文作者:李逍遥JK
    原文地址: https://www.jianshu.com/p/3fedacf2e3db
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞