ibatis-user-java mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Clinton Begin <clinton.be...@gmail.com>
Subject Re: MapperMethod caching?
Date Fri, 01 Jan 2010 17:01:44 GMT
Do you have some profiler metrics or benchmarks to support the concern?
Even completely unoptimized, I'd be surprised if this presented any sort of
performance challenge on a modern VM.

While the MapperMethod may look slow when you read the code, realize that
most of the for loops will execute either 0 or 1 times.  Or maybe a couple
of times for methods that have multiple parameters or the odd one that has
multiple annotations.  Even then, it's 1 - 4 times against fairly quick
code.  The biggest performance impact is probably some of the string
conversion and concatenation, which could probably be optimized.

More important than the micro-optimizations though, is that MapperMethod is
only ever called on the outermost call from the consumer of a Mapper
interface.  So it's a very high level call... just enough to marshal it down
to a sqlSession.[select,insert,update,delete] call.

Even at 40 TPS (a good benchmark for 1,000,000 concurrent requests in an 8
hour period) you're looking at literally 40 * 4 operations per second at
most.  I wouldn't be overly concerned with those calls.  Even the potential
creation and destruction of maybe a few hundred string objects under that
amount of load, is nothing more than light exercise for the garbage
collector.

I think there may be room for improvement, but not enough to warrant
introducing state into a stateless design.

If you have some interesting profiler metrics that show a potential
bottleneck, I'd be very interested in seeing it.

Cheers,
Clinton

On Fri, Jan 1, 2010 at 9:17 AM, Eduardo Macarron <eduardo.macarron@gmail.com
> wrote:

> Yes Clinton, is just for performance.
>
>
> 2010/1/1 Clinton Begin <clinton.begin@gmail.com>
>
> What problem are you trying to solve, or goal you're trying to achieve by
>> doing this?  Is it strictly a performance consideration?
>>
>> Clinton
>>
>>
>>
>> On Fri, Jan 1, 2010 at 7:31 AM, Eduardo Macarron <
>> eduardo.macarron@gmail.com> wrote:
>>
>>> Fist of all happy new year!
>>>
>>> Some work has been doing on Spring 3 and Ibatis 3 integration.
>>>
>>> Having a look at mappers internals we saw that a new MapperMethod is
>>> created (with some introspection work) on each call to a mapper method. I
>>> wonder if it would be better to build them all during startup or maybe cache
>>> them somehow.
>>>
>>> this is the Jira issue (http://jira.springframework.org/browse/SPR-5991)
>>> Grabriel Axel posted it here some months ago (he opened the issue)
>>>
>>> The main problem with this task is that MapperMethods are not thread safe
>>> and that they hold an SqlSession. Enabling cache would require to make some
>>> changes to MapperMethods. SqlSession should be passed as an argument to
>>> execute instead to its constructor.
>>>
>>>  public MapperMethod(Method method, Configuration configuration) {
>>>     paramNames = new ArrayList<String>();
>>>     paramPositions = new ArrayList<Integer>();
>>>     ...
>>>
>>>   public Object execute(Object[] args, SqlSession sqlSession) {
>>>     Object result;
>>>     if (SqlCommandType.INSERT == type) {
>>>     ...
>>>
>>> And MapperProxy
>>>
>>>   public Object invoke(Object proxy, Method method, Object[] args) throws
>>> Throwable {
>>>     return new MapperMethod(method,
>>> sqlSession.getConfiguration()).execute(args, sqlSession);
>>>   }
>>>
>>>
>>> So for example Spring could have this code to use directly injected
>>> Mappers where SqlSession is got from spring's transaction context.
>>>
>>> private Map<Method, MapperMethod> mapperMethods = new
>>> ConcurrentHashMap<Method, MapperMethod>();
>>>
>>> public <T> T getMapper(final Class<T> type) {
>>>     // mimic iBATIS MapperProxy
>>>     return (T)
>>> java.lang.reflect.Proxy.newProxyInstance(type.getClassLoader(), new Class[]
>>> { type },
>>>             new InvocationHandler() {
>>>                 @Override
>>>                 public Object invoke(final Object proxy, final Method
>>> method, final Object[] args) throws Throwable {
>>>                     return execute(new SqlSessionCallback<T>() {
>>>                         @Override
>>>                         public T doInSqlSession(SqlSession sqlSession)
>>> throws SQLException {
>>>                                // mimic iBATIS MapperProxy
>>>                             Class<?> type = method.getDeclaringClass();
>>>                                 if
>>> (!sqlSession.getConfiguration().hasMapper(type)) {
>>>                                 throw new BindingException("Type " + type
>>> + " is not known to the MapperRegistry.");
>>>                             }
>>>
>>>                             MapperMethod mm = mapperMethods.get(method);
>>>                             if (mm == null) {
>>>                                     mm = new MapperMethod(method,
>>> sqlSession.getConfiguration());
>>>                                     mapperMethods.put(method, mm);
>>>                                 } else {
>>>                                     logger.debug("Returning a cached
>>> mapper method");
>>>                                 }
>>>
>>>                                 return (T) mm.execute(args, sqlSession);
>>>                             }
>>>                         });
>>>                     }
>>>                 });
>>>     }
>>>
>>> Or maybe avoid using directly MapperMethods and access to them thought
>>> the "standard" api SqlSession.getConfiguration().getMapper(impl, sesion) but
>>> in that case caching should be done inside.
>>>
>>> what do you think about this?
>>>
>>>
>>>
>>
>

Mime
View raw message