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?

Reply via email to