Mybatis 에서 집합 크기 를 어떻게 판단 합 니까?

Mybatis 에서 집합 한 size 를 판단 하 는 방법 은 아래 방법 으로 할 수 있 습 니 다.

<if test="null != staffCodeList and staffCodeList.size > 0">
and gui.USER_CODE not in
<foreach collection="staffCodeList" item="staffCode" open="(" separator="," close=")">
#{staffCode}
</foreach>
</if>
마 이 바 티 스 의 사이즈(size)방법 에 구덩이 가 있다 니 경계 하 라!
Mybatis 는 개 원 된 경량급 반자동 화 ORM 프레임 워 크 로 대상 응용 프로그램 과 관계 데이터베이스 에 대한 매 핑 을 더욱 쉽게 한다.
MyBatis 는 xml 설명자 나 주 해 를 사용 하여 대상 을 저장 과정 이나 SQL 문장 과 결합 시 킵 니 다.Mybatis 의 가장 큰 장점 은 응용 프로그램 과 Sql 의 결합 을 해제 하 는 것 입 니 다.sql 문 구 는 Xml Mapper 파일 에 쓰 여 있 습 니 다.
OGNL 표현 식 은 Mybatis 에서 매우 광범 위 하 게 응용 되 고 표현 식 의 유연성 으로 인해 동적 Sql 기능 이 매우 강하 다.
OGNL 은 Object-Graph Navigation Language 의 줄 임 말로 대상 그림 내 비게 이 션 언어 를 대표 한다.
OGNL 은 EL 표현 식 언어 로 자바 대상 의 속성 을 설정 하고 가 져 오 며 목록 을 투영 선택 하고 lambda 표현 식 을 실행 할 수 있 습 니 다.
Ognl 클래스 는 표현 식 을 실행 하 는 데 많은 간편 한 방법 을 제공 합 니 다.Struts 2 가 발표 하 는 버 전 마다 새로운 고위 험 실행 구멍 이 생 긴 것 도 유연 한 OGNL 표현 식 을 사 용 했 기 때 문 입 니 다.
회사 백 엔 드 는 Mybatis 를 데이터 액세스 층 으로 사용 하고 사용 하 는 버 전 은 3.2.3 입 니 다.
온라인 환경 업무 시스템 이 작 동 하 는 과정 에서 당 혹 스 러 운 이상 이 발생 했 습 니 다.이 이상 은 때때로 나타 나 지 않 고 각종 OGNL 표현 식 이 비어 있 는 등 특수 한 상황 에서 이 이상 을 재현 하지 않 습 니 다.
구체 적 인 이상 스 택 정 보 는 다음 과 같 습 니 다.

### Error querying database. Cause: org.apache.ibatis.builder.BuilderException: Error evaluating expression 'list != null and list.size() > 0'. Cause: org.apache.ibatis.ognl.MethodFailedException: Method "size" failed for object [1] [java.lang.IllegalAccessException: Class org.apache.ibatis.ognl.OgnlRuntime can not access a member of class java.util.Collections$SingletonList with modifiers "public"]
### Cause: org.apache.ibatis.builder.BuilderException: Error evaluating expression 'list != null and list.size() > 0'. Cause: org.apache.ibatis.ognl.MethodFailedException: Method "size" failed for object [1] [java.lang.IllegalAccessException: Class org.apache.ibatis.ognl.OgnlRuntime can not access a member of class java.util.Collections$SingletonList with modifiers "public"]
 at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:23) org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:107)
 at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:98)
 at cn.com.shaobingmm.MybatisBugTest$2.run(MybatisBugTest.java:88)
 at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.ibatis.builder.BuilderException: Error evaluating expression 'list != null and list.size() > 0'. Cause: org.apache.ibatis.ognl.MethodFailedException: Method "size" failed for object [1] [java.lang.IllegalAccessException: Class org.apache.ibatis.ognl.OgnlRuntime can not access a member of class java.util.Collections$SingletonList with modifiers "public"]
 at org.apache.ibatis.scripting.xmltags.OgnlCache.getValue(OgnlCache.java
 at:47)
 at org.apache.ibatis.scripting.xmltags.ExpressionEvaluator.evaluateBoolean(ExpressionEvaluator.java:29)
 at org.apache.ibatis.scripting.xmltags.IfSqlNode.apply(IfSqlNode.java:30)
 at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:29)
 at org.apache.ibatis.scripting.xmltags.TrimSqlNode.apply(TrimSqlNode.java:51)
 at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:29)
 at org.apache.ibatis.scripting.xmltags.DynamicSqlSource.getBoundSql(DynamicSqlSource.java:37)
 at org.apache.ibatis.mapping.MappedStatement.getBoundSql(MappedStatement.java:275)
 at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:79)
 at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:104)
 ... 3 more
Caused by: org.apache.ibatis.ognl.MethodFailedException: Method "size" failed for object [1] [java.lang.IllegalAccessException: Class org.apache.ibatis.ognl.OgnlRuntime can not access a member of class java.util.Collections$SingletonList with modifiers "public"]
 at org.apache.ibatis.ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:837)
 at org.apache.ibatis.ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:61)
 at org.apache.ibatis.ognl.OgnlRuntime.callMethod(OgnlRuntime.java:860)
 at org.apache.ibatis.ognl.ASTMethod.getValueBody(ASTMethod.java:73)
 at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:170)
 at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:210)
 at org.apache.ibatis.ognl.ASTChain.getValueBody(ASTChain.java:109)
 at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:170)
 at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:210)
 at org.apache.ibatis.ognl.ASTGreater.getValueBody(ASTGreater.java:49)
 at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:170)
 at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:210)
 at org.apache.ibatis.ognl.ASTAnd.getValueBody(ASTAnd.java:56)
 at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:170)
 at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:210)
 at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:333)
 at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:413)
 at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:395)
 at org.apache.ibatis.scripting.xmltags.OgnlCache.getValue(OgnlCache.java:45)
 ... 12 more
List 의 size()방법 은 Public 가 왜 접근 할 수 없 는 이상 이 생 겼 는 지 분명 하 다.이 문 제 는 매번 발생 하 는 것 이 아니 라 여러 번 의 시 도 를 거 쳐 이 이상 은 테스트 환경 에서 재현 되 지 않 았 다.
이 인 터 페 이 스 는 전체 호출 링크 에서 의 오류 횟수 가 전체 호출 횟수 에서 차지 하 는 비율 이 0.01%이 고 무의식 중 에 병발 문제 가 주기 적 인 시간 내 에 확률 적 으로 발생 하 는 것 을 연상 한다.
아 날로 그 다 중 스 레 드 환경 을 작성 하여 회사 목록 테스트 코드 를 읽 습 니 다:

<mapper namespace="CompanyMapper">
 <select id="getCompanysByIds"resultType="cn.com.shaobingmm.Company">
  select *
  from company
  <where>
   <if test="list != null and list.size() > 0">
    and id in
  <foreach collection="list" item="id" open="(" separator="," close=")">#{id}
</foreach>
   </if>
  </where>
 </select>
</mapper>
다 중 스 레 드 병발 환경 에서 의 압력 측정 코드
상소 이상 창고 정 보 는 병발 환경 에서 과연 재현 되 고 이상 정보 코드 에 따라 이 줄 코드 로 실 행 될 때 이상 이 발생 한다.
이상 정 보 는 OgnlRuntime 류 가 자바 util.collections 의 개인 구성원 Singleton List 에 접근 할 수 없 음 을 나타 낸다.
원본 코드 를 보면 MethodFailed Exception 이상 을 던 질 수 있 습 니 다.invokeMethod 방법 내부 에 잠 글 수 있 습 니 다.

public static Object callAppropriateMethod(OgnlContext context, Object source, Object target, String methodName, String propertyName, List methods, Object[] args) throws MethodFailedException {
  Object reason = null;
  Object[] actualArgs = objectArrayPool.create(args.length);
 
  try {
   Method e = getAppropriateMethod(context, source, target, methodName, propertyName, methods, args, actualArgs);
   if(e == null || !isMethodAccessible(context, source, e, propertyName)) {
    StringBuffer buffer = new StringBuffer();
    if(args != null) {
     int i = 0;
 
     for(int ilast = args.length - 1; i <= ilast; ++i) {
      Object arg = args[i];
      buffer.append(arg == null?NULL_STRING:arg.getClass().getName());
      if(i < ilast) {
       buffer.append(", ");
      }
     }
    }
 
    throw new NoSuchMethodException(methodName + "(" + buffer + ")");
   }
 
   Object var14 = invokeMethod(target, e, actualArgs);
   return var14;
  } catch (NoSuchMethodException var21) {
   reason = var21;
  } catch (IllegalAccessException var22) {
   reason = var22;
  } catch (InvocationTargetException var23) {
   reason = var23.getTargetException();
  } finally {
   objectArrayPool.recycle(actualArgs);
  }
 
  throw new MethodFailedException(source, methodName, (Throwable)reason);
 }
invokeMethod 방법 코드

public static Object invokeMethod(Object target, Method method, Object[] argsArray) throws InvocationTargetException, IllegalAccessException {
  boolean wasAccessible = true;
  if(securityManager != null) {
   try {
    securityManager.checkPermission(getPermission(method));
   } catch (SecurityException var6) {
    throw new IllegalAccessException("Method [" + method + "] cannot be accessed.");
   }
  }
 
  if((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !(wasAccessible = method.isAccessible())) {
   method.setAccessible(true); (1)
  }
 
  Object result = method.invoke(target, argsArray); (3)
  if(!wasAccessible) {
   method.setAccessible(false); (2)
  }
 
  return result;
 }
문 제 는 method 에서 실제 적 으로 공유 변수,즉 예 에서 나타 난 것 이다.

public int java.util.Collections$SingletonList.size()
방법.
첫 번 째 스 레 드 t1~(1)줄 코드 가 method 방법 을 호출 할 수 있 도록 허용 할 때 두 번 째 스 레 드 t2 는(2)method 방법 을 접근 할 수 없 는 것 으로 설정 합 니 다.이 어 t1 이(3)줄 까지 실행 되 기 시 작 했 을 때 이 이상 이 발생 한다.이것 은 매우 전형 적 인 동기 화 문제 다.
Ognl 2.7 은 이 문 제 를 복 구 했 습 니 다.ognl 소스 코드 는 my batis 패키지 에 직접 포장 되 어 있 기 때문에 my batis 3.3.0 버 전에 서도 복구 업 그 레이 드 를 진행 하 였 습 니 다.(주안 점

public static Object invokeMethod(Object target, Method method, Object[] argsArray) throws InvocationTargetException, IllegalAccessException {
  boolean syncInvoke = false;
  boolean checkPermission = false;
  int mHash = method.hashCode();
  synchronized(method) {
   if(_methodAccessCache.get(Integer.valueOf(mHash)) == null || _methodAccessCache.get(Integer.valueOf(mHash)) == Boolean.TRUE) {
    syncInvoke = true;
   }
 
   if(_securityManager != null && _methodPermCache.get(Integer.valueOf(mHash)) == null || _methodPermCache.get(Integer.valueOf(mHash)) == Boolean.FALSE) {
    checkPermission = true;
   }
  }
 
  boolean wasAccessible = true;
  Object result;
  if(syncInvoke) {
   synchronized(method) {
    if(checkPermission) {
     try {
      _securityManager.checkPermission(getPermission(method));
      _methodPermCache.put(Integer.valueOf(mHash), Boolean.TRUE);
     } catch (SecurityException var12) {
      _methodPermCache.put(Integer.valueOf(mHash), Boolean.FALSE);
      throw new IllegalAccessException("Method [" + method + "] cannot be accessed.");
     }
    }
 
    if(Modifier.isPublic(method.getModifiers()) && Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
     _methodAccessCache.put(Integer.valueOf(mHash), Boolean.FALSE);
    } else if(!(wasAccessible = method.isAccessible())) {
     method.setAccessible(true);
     _methodAccessCache.put(Integer.valueOf(mHash), Boolean.TRUE);
    } else {
     _methodAccessCache.put(Integer.valueOf(mHash), Boolean.FALSE);
    }
 
    result = method.invoke(target, argsArray);
    if(!wasAccessible) {
     method.setAccessible(false);
    }
   }
  } else {
   if(checkPermission) {
    try {
     _securityManager.checkPermission(getPermission(method));
     _methodPermCache.put(Integer.valueOf(mHash), Boolean.TRUE);
    } catch (SecurityException var11) {
     _methodPermCache.put(Integer.valueOf(mHash), Boolean.FALSE);
     throw new IllegalAccessException("Method [" + method + "] cannot be accessed.");
    }
   }
 
   result = method.invoke(target, argsArray);
  }
 
  return result;
 }
이상 은 개인 적 인 경험 이 므 로 여러분 에 게 참고 가 되 기 를 바 랍 니 다.여러분 들 도 저 희 를 많이 응원 해 주시 기 바 랍 니 다.만약 잘못 이 있 거나 완전히 고려 하지 않 은 부분 이 있다 면 아낌없이 가르침 을 주시 기 바 랍 니 다.

좋은 웹페이지 즐겨찾기