久久福利_99r_国产日韩在线视频_直接看av的网站_中文欧美日韩_久久一

您的位置:首頁技術文章
文章詳情頁

Mybatis 中如何判斷集合的size

瀏覽:4日期:2023-10-20 08:37:04

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>

補充:警惕,MyBatis的size()方法竟然有坑!

Mybatis是一個開源的輕量級半自動化ORM框架,使得面向對象應用程序與關系數據庫的映射變得更加容易。

MyBatis使用xml描述符或注解將對象與存儲過程或SQL語句相結合。 Mybatis最大優點是應用程序與Sql進行解耦,sql語句是寫在Xml Mapper文件中。

OGNL表達式在Mybatis當中應用非常廣泛,其表達式的靈活性使得動態Sql功能的非常強大。

OGNL是Object-Graph Navigation Language的縮寫,代表對象圖導航語言。

OGNL是一種EL表達式語言,用于設置和獲取Java對象的屬性,并且可以對列表進行投影選擇以及執行lambda表達式。

Ognl類提供了許多簡便方法用于執行表達式的。 Struts2發布的每個版本都會出現的新的高危可執行漏洞也是因為它使用了靈活的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 moreCaused 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類不能夠訪問java.util.Collections的私有成員SingletonList。

查看源代碼發現能夠拋出MethodFailedException異常可以鎖定在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)行的時候就會發生該異常。這是一個很典型的同步問題。

Ognl2.7已經修復了該問題,因為ognl源碼是直接打包內嵌在mybatis包中,mybatis3.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; }

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持好吧啦網。如有錯誤或未考慮完全的地方,望不吝賜教。

標簽: Mybatis 數據庫
相關文章:
主站蜘蛛池模板: 日日爱视频 | 国产一区二区三区在线视频 | 亚洲精品一区二区三区樱花 | 狠狠伊人 | 不卡视频一区 | 亚洲人成人一区二区在线观看 | 精品视频在线观看 | 九九爱爱视频 | 欧美精品一区二区三区手机在线 | 韩日免费视频 | 国精产品一区一区三区免费完 | 黄色片免费在线观看 | 欧美一区二区精品 | 亚洲精品国产综合 | 日日夜夜精品免费视频 | 国产精品久久久久久久久免费丝袜 | 日韩欧美亚洲 | 在线日本中文字幕 | 亚洲视频自拍 | 日本精品在线观看 | 久久久久久精 | 狠狠操狠狠操 | 国产精品九九九 | 日本精品视频在线播放 | 久久久久国产 | 日韩中文在线播放 | 一区二区亚洲 | 日本丶国产丶欧美色综合 | 欧美一区二区三区 | 亚洲精品9999| 日韩在线视频一区 | 精品久久久久久久久久久久 | 国产一级影片 | av免费在线观看网址 | 精品一二三区 | 欧美亚洲日本 | 天天看天天爽 | 噜噜噜噜噜在线视频 | 国产综合视频 | 精品国产乱码久久久久久密桃99 | 九色av |