欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

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

這篇文章將為大家詳細(xì)講解有關(guān)Mybatis中Size()方法的作用是什么,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)建站!專注于網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、微信小程序、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了從江免費(fèi)建站歡迎大家使用!

前言

MyBatis 是一個(gè)開(kāi)源的輕量級(jí)的半自動(dòng)化的 ORM 框架,用于面向?qū)ο蠛完P(guān)系型數(shù)據(jù)庫(kù)的映射,其中 xml  文件,和sql語(yǔ)句結(jié)合,最大的特點(diǎn),應(yīng)用程序sql解耦。OGNL表達(dá)式,是MyBatis中的廣泛應(yīng)用,是一種EL語(yǔ)言,用于設(shè)置和獲取 Java  對(duì)象的屬性,并且可以對(duì)列表進(jìn)行投影和執(zhí)行l(wèi)ambda表達(dá)式,ognl提供了簡(jiǎn)單,便于執(zhí)行的ognl表達(dá)式。一個(gè)線上服務(wù),經(jīng)常會(huì)出現(xiàn)一個(gè)異常,構(gòu)造各種OGNL表達(dá)式為空的情況都會(huì)重現(xiàn)該異常,具體的堆棧信息如下:

### 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,還不可訪問(wèn),該異常在測(cè)試環(huán)境未重現(xiàn),但是在接口的完整調(diào)用鏈路中出錯(cuò)的次數(shù)占總的調(diào)用次數(shù)的0.01%,這是概率性事件。

模擬測(cè)試

編寫(xiě)模擬多線程并發(fā)讀取公司列表的測(cè)試代碼

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

多線程下進(jìn)行壓力測(cè)試

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

上述代碼在并發(fā)的時(shí)候會(huì)出現(xiàn)異常。

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類不能訪問(wèn)

查看源碼,破案

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

問(wèn)題出現(xiàn)在meta是一個(gè)共享變量,即

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

當(dāng),第一個(gè)線程t1到第一行代碼允許method方法可以調(diào)用,第二個(gè)線程t2,執(zhí)行到2把方法method設(shè)置為不可訪問(wèn),接著t1又執(zhí)行,此時(shí)行列3會(huì)發(fā)生異常。

升級(jí)版本

lgnl2.7,已經(jīng)修復(fù)了這個(gè)問(wèn)題,所以修復(fù)后的代碼如下

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

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

網(wǎng)頁(yè)標(biāo)題:Mybatis中Size()方法的作用是什么
分享URL:http://www.chinadenli.net/article0/pegcio.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站排名建站公司商城網(wǎng)站電子商務(wù)外貿(mào)建站品牌網(wǎng)站制作

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站網(wǎng)頁(yè)設(shè)計(jì)