亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

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

Mybatis 中如何判斷集合的size

瀏覽:3日期: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 數據庫
相關文章:
主站蜘蛛池模板: 在线不卡一区二区三区日韩 | 色开心婷婷 | 欧美日韩视频二区三区 | 欧美黑人特大巨黑吊 | 国产福利写真视频在线观看 | 久久国产精品岛国搬运工 | 国产尤物视频在线 | 欧美日韩一区二区三区高清不卡 | 亚洲精品久久久久久下一站 | 国产日比视频 | 精品牛牛影视久久精品 | 国产精品福利资源在线 | 欧美日韩亚洲m码色帝国 | 日本黄色小视频在线观看 | 国产成人精品综合在线 | 亚洲午夜精品专区国产 | 国产一级做a爱免费视频 | 国产精品久久久久久久久久久久 | 成人αv在线视频高清 | 毛片小视频 | 韩国日本一级片 | 六月婷婷七月丁香 | 免费视频日韩 | 色香欲综合成人免费视频 | 欧美桃色| 久久91在线| 成人中文字幕在线高清 | 99久久er热在这里只有精品16 | 91综合国产 | 亚洲精品人成网在线播放影院 | 国产毛片在线高清视频 | 麻豆传媒免费入口 | 欧美经典成人在观看线视频 | 95视频在线观看免费 | aaa一级毛片 | 麻豆视传媒短视频网站-欢迎您 | 国产最新网址 | 一级毛片无遮挡免费全部 | 亚洲性影院 | 国产午夜视频在永久在线观看 | 国产精品久久久久久久久电影网 |