mybatis源码解析(七)-当mybatis一级缓存遇上spring

版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/u011647962/article/details/79713284

mybatis源码解析(一)-开篇
mybatis源码解析(二)-加载过程
mybatis源码解析(三)-SqlSession.selectOne类似方法调用过程
mybatis源码解析(四)-Mapper方法调用过程
mybatis源码解析(五)-mybatis如何实现的事务控制
mybatis源码解析(六)-配合spring-tx实现事务的原理
mybatis源码解析(七)-当mybatis一级缓存遇上spring

转载请标明出处:
https://blog.csdn.net/bingospunky/article/details/79713284
本文出自马彬彬的博客

mybatis一级缓存

mybatis一级缓存的作用范围是SqlSession,可以通过SqlSession的getMapper方法创建Mapper,可以通过是否是一个SqlSession来控制一级缓存的作用域。

当mybatis一级缓存遇上spring

考虑这样的情况:controlle、service、mapper都是使用spring容器管理的,在spring容器中,这些bean都是单例的。由于mapper是单例,mapper中的SqlSession如果是同一个,那么一级缓存就会生效。如果我们执行了一次查询,且查询结果已经被一级缓存了,这时候我们修改数据库里的内容,再去执行这个查询的时候,查询缓存在一级缓存里的内容,这显然是不可取的。事实是:当使用mybatis配合spring使用时,每次使用mapper查询都是新的结果,不会使用一级缓存。那么这是怎么做到的呢?

Mapper中有一个属性叫sqlSession,该属性是SqlSessionTemplate类型的,当需要执行sql时,Mapper会调用这个SqlSessionTemplate对象去执行。
SqlSessionTemplate里有一个属性叫sqlSessionProxy,这个属性是个jdbc代理对象,当SqlSessionTemplate需要去执行sql时,会调用这个jdbc代理去执行的。我们来看下这个jdbc代理的实现:

Code1
org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor

    private class SqlSessionInterceptor implements InvocationHandler {
        private SqlSessionInterceptor() {
        }
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
            Object unwrapped;
            try {
                Object result = method.invoke(sqlSession, args);
                if (!SqlSessionUtils.isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
                    sqlSession.commit(true);
                }
                unwrapped = result;
            } catch (Throwable var11) {
                unwrapped = ExceptionUtil.unwrapThrowable(var11);
                if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
                    SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
                    sqlSession = null;
                    Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException)unwrapped);
                    if (translated != null) {
                        unwrapped = translated;
                    }
                }
                throw (Throwable)unwrapped;
            } finally {
                if (sqlSession != null) {
                    SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
                }
            }
            return unwrapped;
        }
    }

Code1第5行,这个jdbc代理方法被调用时,每次都会创建新的SqlSession对象,这样就可以使一级缓存失效。

下面是这个jdbc代理对象的创建过程:

Code2
org.mybatis.spring.SqlSessionTemplate

    public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
        Assert.notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
        Assert.notNull(executorType, "Property 'executorType' is required");
        this.sqlSessionFactory = sqlSessionFactory;
        this.executorType = executorType;
        this.exceptionTranslator = exceptionTranslator;
        this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionTemplate.SqlSessionInterceptor());
    }

Code2第7行,是这个jdbc代理对象的创建过程,可以看到这个代理过程,没有被代理的对象,应该就是专门为了在配合spring时,实现每次调用SqlSession方法时都产生新的SqlSession吧。

展开阅读全文

没有更多推荐了,返回首页