Return-Path: Delivered-To: apmail-ibatis-user-java-archive@www.apache.org Received: (qmail 41575 invoked from network); 2 Jan 2010 02:55:07 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 2 Jan 2010 02:55:07 -0000 Received: (qmail 81231 invoked by uid 500); 2 Jan 2010 02:55:06 -0000 Delivered-To: apmail-ibatis-user-java-archive@ibatis.apache.org Received: (qmail 81196 invoked by uid 500); 2 Jan 2010 02:55:06 -0000 Mailing-List: contact user-java-help@ibatis.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: user-java@ibatis.apache.org Delivered-To: mailing list user-java@ibatis.apache.org Received: (qmail 81188 invoked by uid 99); 2 Jan 2010 02:55:06 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 02 Jan 2010 02:55:06 +0000 X-ASF-Spam-Status: No, hits=2.2 required=10.0 tests=HTML_MESSAGE,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: domain of clinton.begin@gmail.com designates 74.125.92.150 as permitted sender) Received: from [74.125.92.150] (HELO qw-out-1920.google.com) (74.125.92.150) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 02 Jan 2010 02:54:56 +0000 Received: by qw-out-1920.google.com with SMTP id 14so2676635qwa.60 for ; Fri, 01 Jan 2010 18:54:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:in-reply-to:references :date:message-id:subject:from:to:content-type; bh=1e0B+QXgHrOHj9T1cq+a2fDNbR9yyuP7T7nPkjK/zLg=; b=X1lG6x+6h0BNRTJtmbum7aIcMzHy8mctnDCttjrmcFRc4OgrWYo1xkckik4vJCNlSF 0xFsTm89kcqKHVttx1DUgz6oBaXdhDQdzmcqxKh3aOY5oiQ5F7d9HQNxSf3L7I1csarx w3LVlne+a8hiw776h8w9mJNFesddSwGvnr+68= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type; b=Q5YZYC9AEGUNpn5Hin1yWcxFqrAAqBrw9GZMJ5REbtpJG+jlXN3bIbz0UAgwviSMvj XR4If5lURNQrOlhQlMdot+l1RP3RmCs2nS31Yl688jhB6LqsZm9Xie2awhy/onbAGDOa +F/qNXpObDPLoq38tpXVPobfca86KMqq1FjuQ= MIME-Version: 1.0 Received: by 10.224.91.196 with SMTP id o4mr10033569qam.233.1262400872882; Fri, 01 Jan 2010 18:54:32 -0800 (PST) In-Reply-To: <3cd916fe1001011655m6b2b49bm66d0f6d6a629a28a@mail.gmail.com> References: <3cd916fe1001010215j93d2204h22864f034c87edf6@mail.gmail.com> <3cd916fe1001010631m29419682v7fa832575b6c5b85@mail.gmail.com> <16178eb11001010805h28cbc37fpac3f25ff8dbdf440@mail.gmail.com> <3cd916fe1001010817n3e408c9eq7080db2a72244a8@mail.gmail.com> <16178eb11001010901o24fda5b4yf3466e998c826b85@mail.gmail.com> <3cd916fe1001011257m2433b521w95ba908a02959307@mail.gmail.com> <16178eb11001011343x26be4458j4473bb4f47208a50@mail.gmail.com> <3cd916fe1001011655m6b2b49bm66d0f6d6a629a28a@mail.gmail.com> Date: Fri, 1 Jan 2010 19:54:32 -0700 Message-ID: <16178eb11001011854x56e3c680ge6861de136802bec@mail.gmail.com> Subject: Re: MapperMethod caching? From: Clinton Begin To: user-java@ibatis.apache.org Content-Type: multipart/alternative; boundary=000feaf0b1ce97ab02047c259be5 X-Virus-Checked: Checked by ClamAV on apache.org --000feaf0b1ce97ab02047c259be5 Content-Type: text/plain; charset=ISO-8859-1 Yes, regardless of what we do with MapperMethods, Spring should definitely not be involved at that level. I consider that to be pretty deep in the system implementation, and so it's subject to changes... possibly even something like this one. We don't want Spring integration to break every time we refactor something. :-) And while I said I'd be judicious with performance improvements, here's an example of one I'll definitely be making: http://issues.apache.org/jira/browse/IBATIS-724 So please keep the ideas and comments coming. Cheers, Clinton On Fri, Jan 1, 2010 at 5:55 PM, Eduardo Macarron wrote: > Thanks for the explanation Clinton. > > But let me just point that I don't think my suggested change breaks this > design principles. > > When Configuration registers a new Mapper record on MapperRegistry, > MapperRegistry could create MapperMethods, hold them on a Map (maybe instead > of the Set it uses now), and pass this Map to MapperProxy so that it simply > uses its content and does not create any new Object. > > Regardless I got to all this while digging into internals for integrating > Ibatis with Spring, trying to cache this MapperMethods at Spring layer, and > finding that... it was not possible! But maybe we'd better go back and > propose an implementation much more compilant to Ibatis api, forget about > MapperMethods and let Ibatis handle them in the way it prefers. > > Thanks again for your time and for your patience. Hope that GA comes soon!! > > > 2010/1/1 Clinton Begin > >> Thanks Eduardo. I'm open to design suggestions, but will be judicious >> about performance related refactorings or anything that introduces state >> into the execution engine. >> >> Here's a bit of design background: >> >> When you read down the package structure of the org.apache.ibatis, >> generally all state is ultimately stored within the Configuration class and >> the various objects that it collects and manages. Most of these are in the >> mapping and cache packages. The entire execution package (the 'execution >> engine') is stateless (perhaps with one or two exceptions that I cannot >> even recall at the moment). Every other package contains various >> supporting utility classes. >> >> So between the mapping package and the execution package, you have 99% of >> what's important to iBATIS. The mapping package is the state, largely dumb >> state. The execution package is the stateless and contains all of the >> behavior and logic. >> >> This separation is important to keeping the design as simple as possible. >> iBATIS 1 used a "smart object" design, where all state and behavior was >> co-located, that was inflexible and messy. iBATIS 2 used a stateful >> execution pipeline that was very fast, but extremely complicated. Few could >> understand that code. iBATIS 3 focuses heavily on code that's both flexible >> and easier to read, possibly at the cost of a bit of performance, until it >> becomes a problem. >> >> I've been really happy with this focus, as your suggestions are proof that >> the code is succeeding (at least better than its predecessors) in that >> you're able to read it, follow along, figure it out and make suggestions. >> >> They are most welcome, even if we don't accept every one. >> >> Cheers, >> Clinton >> >> >> >> On Fri, Jan 1, 2010 at 1:57 PM, Eduardo Macarron < >> eduardo.macarron@gmail.com> wrote: >> >>> Clinton, you are completely right. On current design, and doing some very >>> basic measures, caching MapperMethods does not provide a significant >>> performance improvement. In my laptop, building a MapperMethod for a simple >>> method requires about 13 microseconds and getting if from a map is about 4 >>> microseconds. So as I said caching does not make a big difference. >>> >>> I wanted just to point that current design disables caching because >>> MapperMethods depend on sessions. That dependency seems unnecesary and >>> removing it with what seems a simple change may open the way to caching. >>> >>> I don't know if MapperMethod creation will be heavier in future versions. >>> For example climbing up in interface hierarchy, filtering java.lang.Object >>> method calls like toString(), performing more checks or maybe other features >>> yet to come. In fact some "caching" is already been done because mappers >>> methods are procesed to search statement annotations during startup. >>> >>> Anyway I am aware of the current status of the project and also that any >>> change should have a good reason to be done. >>> >>> 2010/1/1 Clinton Begin >>> >>>> 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 >>>>> >>>>> 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(); >>>>>>> paramPositions = new ArrayList(); >>>>>>> ... >>>>>>> >>>>>>> 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 mapperMethods = new >>>>>>> ConcurrentHashMap(); >>>>>>> >>>>>>> public T getMapper(final Class 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() { >>>>>>> @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? >>>>>>> >>>>>>> >>>>>>> >>>>>> >>>>> >>>> >>> >> > --000feaf0b1ce97ab02047c259be5 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Yes, regardless of what we do with MapperMethods, Spring should definitely = not be involved at that level.=A0 I consider that to be pretty deep in the = system implementation, and so it's subject to changes... possibly even = something like this one.=A0

We don't want Spring integration to break every time we refactor so= mething.=A0 :-)

And while I said I'd be judicious with performa= nce improvements, here's an example of one I'll definitely be makin= g:=A0 http://is= sues.apache.org/jira/browse/IBATIS-724

So please keep the ideas and comments coming.

Cheers,
Clinto= n

On Fri, Jan 1, 2010 at 5:55 PM, Eduardo= Macarron <eduardo.macarron@gmail.com> wrote:
Thanks for the ex= planation Clinton.

But let me just point that I don't think my s= uggested change breaks this design principles.

When Configuration registers a new Mapper record on MapperRegistry, Map= perRegistry could create MapperMethods, hold them on a Map (maybe instead o= f the Set it uses now), and pass this Map to MapperProxy so that it simply = uses its content and does not create any new Object.

Regardless I got to all this while digging into internals for integrati= ng Ibatis with Spring, trying to cache this MapperMethods at Spring layer, = and finding that... it was not possible! But maybe we'd better go back = and propose an implementation much more compilant to Ibatis api, forget abo= ut MapperMethods and let Ibatis handle them in the way it prefers.

Thanks again for your time and for your patience. Hope that GA comes so= on!!


20= 10/1/1 Clinton Begin <clinton.begin@gmail.com>
Thanks Eduardo.= =A0 I'm open to design suggestions, but will be judicious about perform= ance related refactorings or anything that introduces state into the execut= ion engine.

Here's a bit of design background:

When you read down the package structure of the org.apache.ibatis, gene= rally all state is ultimately stored within the Configuration class and the= various objects that it collects and manages.=A0 Most of these are in the = mapping and cache packages.=A0 The entire execution package (the 'execu= tion engine') is stateless (perhaps with one or two exceptions that I c= annot even=A0 recall at the moment).=A0 Every other package contains variou= s supporting utility classes.

So between the mapping package and the execution package, you have 99% = of what's important to iBATIS.=A0 The mapping package is the state, lar= gely dumb state.=A0 The execution package is the stateless and contains all= of the behavior and logic.=A0

This separation is important to keeping the design as simple as possibl= e.=A0 iBATIS 1 used a "smart object" design, where all state and = behavior was co-located, that was inflexible and messy.=A0 iBATIS 2 used a = stateful execution pipeline that was very fast, but extremely complicated.= =A0 Few could understand that code.=A0 iBATIS 3 focuses heavily on code tha= t's both flexible and easier to read, possibly at the cost of a bit of = performance, until it becomes a problem.

I've been really happy with this focus, as your suggestions are pro= of that the code is succeeding (at least better than its predecessors) in t= hat you're able to read it, follow along, figure it out and make sugges= tions.

They are most welcome, even if we don't accept every one.=A0
Cheers,
Clinton


On Fri, Jan 1, 2010 at 1:57 PM, Eduardo= Macarron <eduardo.macarron@gmail.com> wrote:
Clinton, you are = completely right. On current design, and doing some very basic measures, ca= ching MapperMethods does not provide a significant performance improvement.= In my laptop, building a MapperMethod for a simple method requires about 1= 3 microseconds and getting if from a map is about 4 microseconds. So as I s= aid caching does not make a big difference.

I wanted just to point that current design disables caching because Map= perMethods depend on sessions. That dependency seems unnecesary and removin= g it with what seems a simple change may open the way to caching.

I don't know if MapperMethod creation will be heavier in future version= s. For example climbing up in interface hierarchy, filtering java.lang.Obje= ct method calls like toString(), performing more checks or maybe other feat= ures yet to come. In fact some "caching" is already been done bec= ause mappers methods are procesed to search statement annotations during st= artup.

Anyway I am aware of the current status of the project and also that an= y change should have a good reason to be done.

2010/1/1 Clinton Begin <= ;clinton.begin= @gmail.com>
Do you have some profiler metrics or benchmarks to support the concern?=A0 = Even completely unoptimized, I'd be surprised if this presented any sor= t of performance challenge on a modern VM.=A0

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.=A0 Or maybe a couple of times for methods that have multiple parameters or the odd one that has multiple annotations.=A0 Even then, it's 1 - 4 times again= st fairly quick code.=A0 The biggest performance impact is probably some of the string conversion and concatenation, which could probably be optimized.=A0

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.=A0 So it's a very high level call... ju= st enough to marshal it down to a sqlSession.[select,insert,update,delete] call.=A0

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.=A0 I wouldn't be overly concerned with those calls.=A0 = 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 in= troducing state into a stateless design.=A0

If you have some intere= sting profiler metrics that show a potential bottleneck, I'd be very in= terested in seeing it.=A0

Cheers,
Clinton
<= br>
On Fri, Jan 1, 2010 at 9:17 AM, Eduardo M= acarron <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?=A0 Is it strictly a performance consideration?=A0

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 Sp= ring 3 and Ibatis 3 integration.

Having a look at mappers internals we saw that a new MapperMethod is cr= eated (with some introspection work) on each call to a mapper method. I won= der if it would be better to build them all during startup or maybe cache t= hem somehow.

this is the Jira issue (http://jira.springframework.org/browse/SPR-5= 991) Grabriel Axel posted it here some months ago (he opened the issue)=

The main problem with this task is that MapperMethods are not thread sa= fe and that they hold an SqlSession. Enabling cache would require to make s= ome changes to MapperMethods. SqlSession should be passed as an argument to= execute instead to its constructor.=A0

=A0public MapperMethod(Method method, Configuration configuration) {=A0=A0=A0 paramNames =3D new ArrayList<String>();
=A0=A0=A0 param= Positions =3D new ArrayList<Integer>();
=A0=A0=A0 ...

=A0 p= ublic Object execute(Object[] args, SqlSession sqlSession) {
=A0=A0=A0 Object result;
=A0=A0=A0 if (SqlCommandType.INSERT =3D=3D type= ) {
=A0=A0=A0 ...

And MapperProxy

=A0 public Object invoke= (Object proxy, Method method, Object[] args) throws Throwable {
=A0=A0= =A0 return new MapperMethod(method, sqlSession.getConfiguration()).execute(= args, sqlSession);
=A0 }


So for example Spring could have this code to use directly= injected Mappers where SqlSession is got from spring's transaction con= text.

private Map<Method, MapperMethod> mapperMethods =3D new = ConcurrentHashMap<Method, MapperMethod>();

public <T> T getMapper(final Class<T> type) {
=A0=A0=A0 = // mimic iBATIS MapperProxy
=A0=A0=A0 return (T) java.lang.reflect.Proxy= .newProxyInstance(type.getClassLoader(), new Class[] { type },
=A0=A0=A0= =A0=A0=A0 =A0=A0=A0 new InvocationHandler() {
=A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 @Override
=A0=A0=A0 =A0=A0=A0 = =A0=A0=A0 =A0=A0=A0 public Object invoke(final Object proxy, final Method m= ethod, final Object[] args) throws Throwable {
=A0=A0=A0 =A0=A0=A0 =A0= =A0=A0 =A0=A0=A0 =A0=A0=A0 return execute(new SqlSessionCallback<T>()= {
=A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 @Override
= =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 public T doInSq= lSession(SqlSession sqlSession) throws SQLException {
=A0=A0=A0 =A0=A0= =A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 // mimic i= BATIS MapperProxy
=A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0 Class<?> type =3D method.getDeclaringClass(); =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 if (!sqlSession.getConfiguration().hasMapper(type)) {
=A0= =A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 throw new BindingException("Type " + type + " is n= ot known to the MapperRegistry.");
=A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= }

=A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 MapperMethod mm =3D mapperMethods.get(method);
=A0=A0=A0 =A0= =A0=A0 =A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 if (mm =3D= =3D null) {
=A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 =A0=A0=A0 mm =3D new MapperMethod(method, sqlSe= ssion.getConfiguration());
=A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 =A0=A0=A0 mapperMethods.put(method, mm);
=A0=A0=A0 =A0=A0= =A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 } els= e {
=A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0 =A0=A0=A0 logger.debug("Returning a cached mapper m= ethod");
=A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 }
=A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0
=A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 return (T) mm.execute(args, sqlSession);
=A0= =A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 }
=A0= =A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 });
=A0=A0=A0 = =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 =A0=A0=A0 }
=A0=A0=A0 =A0=A0=A0 =A0=A0=A0 = =A0=A0=A0 });
=A0=A0=A0 }

Or maybe avoid using directly MapperMethods and access t= o them thought the "standard" api SqlSession.getConfiguration().g= etMapper(impl, sesion) but in that case caching should be done inside.
<= br> what do you think about this?









--000feaf0b1ce97ab02047c259be5--