久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

Mybatis中Size()方法的作用是什么

160次閱讀
沒有評論

共計 10140 個字符,預計需要花費 26 分鐘才能閱讀完成。

這篇文章將為大家詳細講解有關 Mybatis 中 Size() 方法的作用是什么,文章內容質量較高,因此丸趣 TV 小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

前言

MyBatis 是一個開源的輕量級的半自動化的 ORM 框架,用于面向對象和關系型數據庫的映射,其中 xml   文件,和 sql 語句結合,最大的特點,應用程序 sql 解耦。OGNL 表達式,是 MyBatis 中的廣泛應用,是一種 EL 語言,用于設置和獲取 Java   對象的屬性,并且可以對列表進行投影和執行 lambda 表達式,ognl 提供了簡單,便于執行的 ognl 表達式。一個線上服務,經常會出現一個異常,構造各種 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

多線程下進行壓力測試

String resource =  mybatis-config.xml  InputStream in = null; try { in = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in); final List Long  ids = Collections.singletonList(1L); final SqlSession session = sqlSessionFactory.openSession(); final CountDownLatch mCountDownLatch = new CountDownLatch(1); for (int i = 0; i   50; i++) { Thread thread = new Thread(new Runnable() { public void run() { try { mCountDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } for (int k = 0; k   100; k++) { session.selectList( CompanyMapper.getCompanysByIds , ids); } } }); thread.start(); } mCountDownLatch.countDown(); synchronized (MybatisBugTest.class) { try { MybatisBugTest.class.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } catch (IOException e) { e.printStackTrace(); } catch (Throwable e) { e.printStackTrace(); } finally { if (in != null) try { in.close(); } catch (IOException e) { e.printStackTrace(); } }

上述代碼在并發的時候會出現異常。

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)

異常信息表明 ognlRuntime 類不能訪問

查看源碼,破案

java.util.Collections 的私有成員 SingletonList。查看源代碼,可以知道鎖定在 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); }

其方法代碼

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; }

問題出現在 meta 是一個共享變量,即

public int java.util.Collections$SingletonList.size()

當,第一個線程 t1 到第一行代碼允許 method 方法可以調用,第二個線程 t2,執行到 2 把方法 method 設置為不可訪問,接著 t1 又執行,此時行列 3 會發生異常。

升級版本

lgnl2.7,已經修復了這個問題,所以修復后的代碼如下

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; }

關于 Mybatis 中 Size() 方法的作用是什么就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-08-03發表,共計10140字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 济宁市| 鹤庆县| 新河县| 宽城| 都兰县| 阜城县| 桦南县| 新津县| 永川市| 达孜县| 渝中区| 柳州市| 北宁市| 乐东| 珠海市| 舟山市| 阜新| 绍兴县| 弥勒县| 浦江县| 湾仔区| 休宁县| 乡城县| 奈曼旗| 吉安市| 佛教| 东港市| 天津市| 新干县| 武川县| 阳信县| 漯河市| 甘孜县| 丹棱县| 永平县| 南通市| 丰城市| 东城区| 南康市| 大庆市| 萨嘎县|