Mybatis是一个开源的轻量级半自动化ORM框架,使得面向对象应用程序与关系数据库的映射变得更加容易。
MyBatis使用xml描述符或注解将对象与存储过程或SQL语句相结合。Mybatis最大优点是应用程序与Sql进行解耦,sql语句是写在Xml Mapper文件中。
OGNL表达式在Mybatis当中应用非常广泛,其表达式的灵活性使得动态Sql功能的非常强大。OGNL是Object-Graph Navigation Language的缩写,代表对象图导航语言。
具体异常堆栈信息如下:
### 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
<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)
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;
}
public int java.util.Collections$SingletonList.size()
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;
}
作者:蓬蒿
来源:zhuanlan.zhihu.com/p/30085658
- END -
点击「阅读原文」带你飞~
本文分享自微信公众号 - Java技术栈(javastack)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
来源:oschina
链接:https://my.oschina.net/u/3756234/blog/4576711