zoukankan      html  css  js  c++  java
  • 记录一次bug解决过程:mybatis中$和#的使用

    一、总结

      mybatis中使用sqlMap进行sql查询时,经常需要动态传递参数。动态SQL是mybatis的强大特性之一,也是它优于其他ORM框架的一个重要原因。mybatis在对sql语句进行预编译之前,会对sql进行动态解析,解析为一个BoundSql对象,也是在此处对动态SQL进行处理的。在动态 SQL 解析阶段,#{ }和${ }会有不同的表现,#{ }解析为一个JDBC预编译语句(prepared statement)的参数标记符。

      一个 #{ } 被解析为一个参数占位符 ? 。${ } 仅仅为一个纯碎的 string 替换,在动态 SQL 解析阶段将会进行变量替换。

    二、Bug描述

    前端传入参数:

    skip:0
    take:10
    ruleName:A,B,C

    业务层处理:

    package SQL;
    
    /**
     * 将前端多选参数转义为SQL语句内容
     */
    public class SQLUtil {
    
        private final static String REPLACECHAR_COMMA     = ",";
        private final static String REPLACECHAR_SEMICOLON = ";";
    
        public static void main(String[] args) {
            String s1 = "A,B,C";
            String s2 = "A B C";
            System.out.println("逗号分隔:" + formatInStr(s1));
            System.out.println("空格分隔:" + formatInStr(s2));
        }
    
        private static String formatInStr(String queryStr) {
            return queryInStr(sliptQueryStr(queryStr));
        }
    
        private static String[] sliptQueryStr(String queryStr) {
            if (null == queryStr || "".equals(queryStr.trim())) return null;
            queryStr = queryStr.replaceAll(SQLUtil.REPLACECHAR_COMMA, " ").replaceAll(REPLACECHAR_SEMICOLON, " ");
            return queryStr.split("\s+");
        }
    
        private static String queryInStr(String[] queryStrs) {
            if (null == queryStrs || 0 == queryStrs.length) return null;
            StringBuffer buf = new StringBuffer();
            for (int i = 0; i < queryStrs.length; i++) {
                if (i != 0) buf.append(",");
                buf.append("'").append(queryStrs[i]).append("'");
            }
            return buf.toString();
        }
    }

    Mapper层处理:

    //错误的处理
    <if test="ruleName != null and ruleName != ''">
        AND a.rule_name IN (#{ruleName})
    </if>
    
    //正确的处理
    <if test="ruleName != null and ruleName != ''">
        AND a.rule_name IN (${ruleName})
    </if>

    日志描述:

    [DEBUG] [2016-08-02 17:42:42.226] [qtp1457334982-157] java.sql.Connection - ==>  Preparing: SELECT a.id, a.is_valid, a.rule_lable, a.rule_name, a.type, b.sp_id, b.sp_name, 
          a.rule_content, c.user_name, a.gmt_modified, a.ordering FROM idc_logistics_assign_rules a LEFT JOIN app_user c on c.work_no=a.modifier and c.is_deleted='n',
          idc_sp_info b WHERE a.is_deleted = 'n' AND b.is_deleted = 'n' AND a.sp_id = b.sp_id AND a.rule_name IN (?) ORDER BY ordering asc limit ?, ? [DEBUG] [2016-08-02 17:42:42.226] [qtp1457334982-157] java.sql.PreparedStatement - ==> Parameters: 'A','B'(String), 0(Integer), 10(Integer)

    结果分析:mapper层对sql有预编译处理,对于#有占位符?,但是对于$会直接替换。

    参考:http://www.tuicool.com/articles/VvyMN3A

  • 相关阅读:
    基础架构:一条SQL查询语句是如何执行的?
    常用的字符串转换日期格式
    JSONObject.fromObject(map)(JSON与JAVA数据的转换)
    ModelAndView的介绍
    Springmvc常用注解
    @PathVariable注解
    @ModelAttribute运用详解
    struts2将servlet对象注入到Action中
    为什么要继承ActionSupport?
    mysql中like用法
  • 原文地址:https://www.cnblogs.com/RunForLove/p/5730286.html
Copyright © 2011-2022 走看看