MyBatis에서 $및 # 을 사용하여 발생하는 문제 및 해결 방법

3656 단어 mybatis$#
지난 문장에서 모두에게 소개하였다Mybatis에서 #{}와 ${} 전참의 차이 및 #과 $의 차이 소결 필요하시면 참고하시기 바랍니다.
$및 # 간단한 설명:
# 데이터에 큰따옴표를 붙이는 것과 같고, $는 데이터를 직접 표시하는 것과 같다.
총결산
mybatis에서 sqlMap을 사용하여 sql 조회를 할 때 동적 전달 파라미터가 자주 필요합니다.동적 SQL은 mybatis의 강력한 특성 중 하나이며 다른 ORM 프레임워크보다 우수한 중요한 원인이기도 하다.mybatis는 sql 문장을 미리 컴파일하기 전에 sql에 대해 동적 해석을 하고 boundSql 대상으로 해석하며 여기서 동적 SQL을 처리합니다.동적 SQL 해석 단계에서 #{}와 ${}는 서로 다른 표현을 할 수 있으며, #{}는 JDBC 사전 컴파일된 문장(prepared statement)의 매개 변수 표기자로 해석됩니다.
하나의 #{} 이 매개 변수 자리 표시자로 해석되었습니까?.${} 단지 하나의 순수한 스트링 교체일 뿐, 동적 SQL 해석 단계에서 변수 교체가 진행될 것입니다.
2. 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();
}
}
매퍼 레이어 처리:

// 
<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)
결과 분석: 마퍼층은 sql에 대해 사전 컴파일 처리가 있고, #에 대해 자리 차지 문자가 있다?,그러나 $에 대해서는 직접 대체됩니다.
PS: MyBatis 정렬 시 order by 동적 매개 변수를 사용할 때 # 대신 $로 주의해야 합니다.
문자열 대체
기본적으로 # {} 형식의 구문을 사용하면 MyBatis가 사전 처리 문장 속성을 만들고 이를 배경으로 안전한 값을 설정합니다(예:?).이렇게 하는 것은 매우 안전하고 신속하며 최선의 방법이다. 때로는 SQL 문장에 변하지 않는 문자열을 직접 삽입하고 싶을 뿐이다.예를 들어, ORDER BY와 같이 다음과 같이 사용할 수 있습니다.

 ORDER BY ${columnName}
여기서 MyBatis는 문자열을 수정하거나 이스케이프하지 않습니다.
중요: 사용자가 출력한 내용을 받아들여 문장에 변하지 않는 문자열을 제공하는 것은 안전하지 않다.이것은 잠재적인 SQL 주입 공격을 초래할 수 있기 때문에 사용자가 이 필드를 입력하거나 통상적으로 스스로 의미를 바꾸어 검사하는 것을 허락해서는 안 된다.

좋은 웹페이지 즐겨찾기