MyBatis also has concurrency problems

In order to save dalaos time, let me first conclude: it is indeed a problem, issue link: github.com/mybatis/myb…[1]

The following is the source code analysis link and processing process. If you are interested, you can take a look.

Bugs need to be solved at any time! It won’t work without solving it. Think about it, you just arrived at the company in the morning, turned on the computer, wrote the requirements and listened to the song, and suddenly you were hit… So days without bugs are good days!

When I got on the server, I saw that Mybatis reported an error. The interface was still a very frequent interface. When I thought about it, it was over and the performance was probably not guaranteed.

2023-08-08 09:52:05,386|aaaaaaaaa|XXXXXXXXXXXXXX|unknown exception occurred
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Error evaluating expression 'projects != null and projects.size() > 0 '. Cause: org.apache.ibatis.ognl.MethodFailedException : Method "size" failed for object [aaa,bbb,ccc] [java.lang.IllegalAccessException: Class org.apache.ibatis.ognl.OgnlRuntime can not access a member of class java.util.Arrays$ArrayList with modifiers "public "]
        at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:75) ~[mybatis-spring-1.2.2.jar:1.2.2]
        at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:371) ~[mybatis-spring-1.2.2.jar:1.2.2]
        at com.sun.proxy.$Proxy57.selectList(Unknown Source) ~[na:na]
        at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:198) ~[mybatis-spring-1.2.2.jar:1.2.2]
        at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:119) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:63) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:52) ~[mybatis-3.2.8.jar:3.2.8]
        at com.sun.proxy.$Proxy102.queryExperienceCardOrder(Unknown Source) ~[na:na]
      //Business related stack, not posted for safety reasons
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.6.RELEASE.jar:4.3.6.RELEASE]
        at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:652) ~[spring-aop-4.3.6.RELEASE.jar:4.3.6.RELEASE]
        at com.xxxxxxxxxxxxxxxxxxxxxx$$EnhancerBySpringCGLIB$$b85a94bd.queryHasExperienceCardNew(<generated>) ~[zuhao-user-service-1.0.0.jar:na]
        at sun.reflect.GeneratedMethodAccessor564.invoke(Unknown Source) ~[na:na]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131]
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333) ~[spring-aop-4.3.6.RELEASE.jar:4.3.6.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) [spring-aop-4.3.6.RELEASE.jar:4.3.6.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) [spring-aop-4.3.6.RELEASE.jar:4.3.6.RELEASE]
        at xxxxxxxxxxxxx.common.interceptor.ApiInterceptor.invoke(ApiInterceptor.java:79) ~[common-0.0.9-20211228.052440-12.jar:na]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.3.6.RELEASE.jar:4.3.6.RELEASE]
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) [spring-aop-4.3.6.RELEASE.jar:4.3.6.RELEASE]
        at com.sun.proxy.$Proxy185.queryHasExperienceCardNew(Unknown Source) [na:na]
        at com.alibaba.dubbo.common.bytecode.Wrapper36.invokeMethod(Wrapper36.java) [na:2.5.3]
        at com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory$1.doInvoke(JavassistProxyFactory.java:46) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker.invoke(AbstractProxyInvoker.java:72) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:53) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.filter.ExceptionFilter.invoke(ExceptionFilter.java:64) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.monitor.support.MonitorFilter.invoke$original$LFhJaVNd(MonitorFilter.java:65) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.monitor.support.MonitorFilter.invoke$original$LFhJaVNd$accessor$urPnHrIw(MonitorFilter.java) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.monitor.support.MonitorFilter$auxiliary$RJHyKBeq.call(Unknown Source) [dubbo-2.5.3.jar:2.5.3]
        at org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstMethodsInter.intercept(InstMethodsInter.java:86) [skywalking-agent.jar:8.16.0]
        at com.alibaba.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.filter.TimeoutFilter.invoke(TimeoutFilter.java:42) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.protocol.dubbo.filter.TraceFilter.invoke(TraceFilter.java:78) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.filter.ContextFilter.invoke(ContextFilter.java:60) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.filter.GenericFilter.invoke(GenericFilter.java:112) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.filter.ClassLoaderFilter.invoke(ClassLoaderFilter.java:38) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.filter.EchoFilter.invoke(EchoFilter.java:38) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol$1.reply(DubboProtocol.java:108) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.handleRequest(HeaderExchangeHandler.java:84) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.received(HeaderExchangeHandler.java:170) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:52) [dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:82) [dubbo-2.5.3.jar:2.5.3]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_131]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_131]
        at java.lang.Thread.run(Thread.java:748) [na:1.8.0_131]
Caused by: org.apache.ibatis.builder.BuilderException: Error evaluating expression 'projects != null and projects.size() > 0 '. Cause: org.apache.ibatis.ognl.MethodFailedException: Method "size" failed for object [uhaozhu, renthaoxiao, renthaoku] [java.lang.IllegalAccessException: Class org.apache.ibatis.ognl.OgnlRuntime can not access a member of class java.util.Arrays$ArrayList with modifiers "public"]
        at org.apache.ibatis.scripting.xmltags.OgnlCache.getValue(OgnlCache.java:47) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.scripting.xmltags.ExpressionEvaluator.evaluateBoolean(ExpressionEvaluator.java:32) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.scripting.xmltags.IfSqlNode.apply(IfSqlNode.java:33) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:32) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.scripting.xmltags.TrimSqlNode.apply(TrimSqlNode.java:54) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:32) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.scripting.xmltags.TrimSqlNode.apply(TrimSqlNode.java:54) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:32) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.scripting.xmltags.DynamicSqlSource.getBoundSql(DynamicSqlSource.java:40) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.mapping.MappedStatement.getBoundSql(MappedStatement.java:278) ~[mybatis-3.2.8.jar:3.2.8]
        at com.github.pagehelper.PageInterceptor.intercept(PageInterceptor.java:83) ~[pagehelper-5.1.4.jar:na]
        at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:60) ~[mybatis-3.2.8.jar:3.2.8]
        at com.sun.proxy.$Proxy234.query(Unknown Source) ~[na:na]
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:108) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:102) ~[mybatis-3.2.8.jar:3.2.8]
        at sun.reflect.GeneratedMethodAccessor347.invoke(Unknown Source) ~[na:na]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131]
        at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:358) ~[mybatis-spring-1.2.2.jar:1.2.2]
        ... 54 common frames omitted
Caused by: org.apache.ibatis.ognl.MethodFailedException: Method "size" failed for object [aaa,bbb,ccc]
        at org.apache.ibatis.ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:837) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:61) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.ognl.OgnlRuntime.callMethod(OgnlRuntime.java:860) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.ognl.ASTMethod.getValueBody(ASTMethod.java:73) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:170) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:210) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.ognl.ASTChain.getValueBody(ASTChain.java:109) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:170) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:210) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.ognl.ASTGreater.getValueBody(ASTGreater.java:49) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:170) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:210) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.ognl.ASTAnd.getValueBody(ASTAnd.java:56) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:170) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:210) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:333) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:310) ~[mybatis-3.2.8.jar:3.2.8]
        at org.apache.ibatis.scripting.xmltags.OgnlCache.getValue(OgnlCache.java:45) ~[mybatis-3.2.8.jar:3.2.8]
        ... 72 common frames omitted


I quickly checked the calling status of this interface. Most of them were fine. Occasionally, I made such an error (not bad, not bad).

Checking the error location based on the stack, I am a bit confused. Is there a problem here? Then we can only look at the source code

After investigation, the method used in the ognl expression will obtain the method through reflection and cache it into a static variable. Therefore, there is a multi-threaded state, causing concurrency problems. See below.

Here is the logic of the cache method, org.apache.ibatis.ognl.OgnlRuntime#getMethods(java.lang.Class, boolean) If you are interested, you can read it yourself

This is the bug point. If there are too many calls, thread A changes it to true, but before the method is called, thread B changes it to false. At this time, the call fails. Isn’t this a pitfall?

Sure enough, there is this issue in mybatis search: github.com/mybatis/myb…[2]

The solution given by the author is to upgrade mybatis.

You thought that was the end?

It is impossible to upgrade, it is impossible to upgrade in this life, the code is so stable, every line is like a poem [dog head]

Just kidding, let’s see how to avoid

The reason is that Arrays.asList returns an inner class, which is private. Therefore, (!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) This condition is true and the setting is entered accessible was later set back to its original state.

  • Problem: If the methods and classes of objects that require ognl are not public, there will be concurrency problems

  • Solution 1: For concurrency issues, upgrade Mybatis

  • Solution 2: Lists.newArrayList or other writing methods instead, check to see if the inner class is private

If you have any questions, please leave a message to point them out.

Reference materials

[1]

https://github.com/mybatis/mybatis-3/pull/384: https://link.juejin.cn/?target=https://github.com/mybatis/mybatis-3/pull/ 384

[2]

https://github.com/mybatis/mybatis-3/pull/384: https://link.juejin.cn/?target=https://github.com/mybatis/mybatis-3/pull/ 384