mybatis源码分析

1、mybatis源码分析面试

1.mybatis功能架构sql

2. SQL调用过程(mybatis工做原理)数据库

mybatis经过配置文件建立sqlsessionFactory,sqlsessionFactory根据配置文件,配置文件来源于两个方面:一个是xml,一个是Java中的注解,获取sqlSession。SQLSession包含了执行sql语句的全部方法,能够经过SQLSession直接运行映射的sql语句,完成对数据的增删改查和事物的提交工做,用完以后关闭SQLSession。 缓存

3. mybatis的SqlSessionFactory 与 SqlSession.安全

(1)首先,SqlSessionFactoryBuilder去读取mybatis的配置文件,而后build一个DefaultSqlSessionFactory。session

(2)当咱们获取到SqlSessionFactory以后,就能够经过SqlSessionFactory去获取SqlSession对象。mybatis

4. 利器之MapperProxy:架构

在mybatis中,经过MapperProxy动态代理我们的dao(mapper), 也就是说, 当我们执行本身写的dao里面的方法的时候,实际上是对应的mapperProxy在代理。app

(1)经过SqlSession从Configuration中获取。框架

(2)SqlSession把包袱甩给了Configuration, 接下来就看看Configuration。

(3)Configuration不要这烫手的山芋,接着甩给了MapperRegistry, 那咱看看MapperRegistry。

(4)MapperRegistry经过调用newInstance动态代理咱们写的dao接口。

5.Excutor

6.mybatis的缓存

6.1 一级缓存的做用域是SqlSession

Executor接口的实现类是由Configuration构造的:

public Executor newExecutor(Transaction transaction, ExecutorType executorType, boolean autoCommit) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
      executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
      executor = new CachingExecutor(executor, autoCommit);
    }
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
}

最后咱们发现若是cacheEnabled这个属性为true的话,那么executor会被包一层装饰器,这个装饰器是CachingExecutor。其中cacheEnabled这个属性是mybatis总配置文件中settings节点中cacheEnabled子节点的值,默认就是true,也就是说咱们在mybatis总配置文件中不配cacheEnabled的话,它也是默认为打开的。

CachingExecutor执行sql的时候到底作了什么?

public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    Cache cache = ms.getCache();//这儿执行的是二级缓存
    if (cache != null) {
      flushCacheIfRequired(ms);
      if (ms.isUseCache() && resultHandler == null) { 
        ensureNoOutParams(ms, parameterObject, boundSql);
        if (!dirty) {
          cache.getReadWriteLock().readLock().lock();
          try {
            @SuppressWarnings("unchecked")
            List<E> cachedList = (List<E>) cache.getObject(key);
            if (cachedList != null) return cachedList;
          } finally {
            cache.getReadWriteLock().readLock().unlock();
          }
        }
        List<E> list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
        tcm.putObject(cache, key, list); // issue #578. Query must be not synchronized to prevent deadlocks
        return list;
      }
    }
    return delegate.<E>query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

因为咱们没有开启二级缓存(二级缓存的内容下面会分析),所以这里执行了最后一句话。因此一级缓存最重要的代码就是BaseExecutor的query方法! 这个localCache就是一级缓存!

接下来咱们看下为什么执行新增或更新或删除操做,一级缓存就会被清除这个问题。

CachingExecutor的update方法

public int update(MappedStatement ms, Object parameterObject) throws SQLException {
    flushCacheIfRequired(ms);//这清除的是二级缓存
    return delegate.update(ms, parameterObject);
}

BaseExecutor的update方法:

public int update(MappedStatement ms, Object parameter) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
    if (closed) throw new ExecutorException("Executor was closed.");
    clearLocalCache();
    return doUpdate(ms, parameter);
}

6.2 二级缓存

二级缓存的做用域是全局,换句话说,二级缓存已经脱离SqlSession的控制了。二级缓存的做用域是全局的,二级缓存在SqlSession关闭或提交以后才会生效。

本文就说下最简单的配置,在mapper文件上加上这句配置便可:<cache/>

2、面试相关

1.mybatis是什么? 
mybatis是一个优秀的持久层框架,他对jdbc操做数据库的过程进行了封装,使开发着只用关注sql自己,不用去关注例如注册驱动,加载连接,获得statement,处理结果集等复杂的过程。 
mybatis经过xml或者注解的方式,将要执行的各类sql语句配置起来,并经过Java对象和statement中的sql语句映射生成最终的sql语句,最后由mybatis框架执行sql语句,并将结果映射成Java对象返回。 

2.mybatis解决的问题

  • 使用数据库链接池管理连接,避免了频繁建立了、关闭连接,浪费资源,影响性能的问题。
  • 用xml管理sql语句,让Java代码和sql语句分离,使得代码更易维护。
  • 解决了sql语句参数不定的问题。xml中能够经过where条件决定sql语句的条件参数。mybatis将Java对象映射到sql语句,经过statement的parameterType定义输入参数的类型。
  • mybatis自动将结果集封装成Java对象, 经过statement的resultType定义输出的类型。避免了因sql变化,对结果集处理麻烦的问题。

3. #{}和${}的区别是什么?

#{}是预编译处理,${}是字符串替换。 Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值; Mybatis在处理${}时,就是把${}替换成变量的值。 使用#{}能够有效的防止SQL注入,提升系统安全性。

4.Mybatis是如何进行分页的?分页插件的原理是什么?

Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页,能够在sql内直接书写带有物理分页的参数来完成物理分页功能,也可使用分页插件来完成物理分页。 分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,而后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。

5.什么是延迟加载

  1. 延迟加载的条件:resultMap能够实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具有延迟加载功能。
  2. 延迟加载的好处:
    先从单表查询、须要时再从关联表去关联查询,大大提升 数据库性能,由于查询单表要比关联查询多张表速度要快。
  3. 延迟加载的实例:
    若是查询订单而且关联查询用户信息。若是先查询订单信息便可知足要求,当咱们须要查询用户信息时再查询用户信息。把对用户信息的按需去查询就是延迟加载。

6.Hibernate3与 MyBatis3.1的比较

二者相同点

Hibernate与 MyBatis均可以是经过SessionFactoryBuider由XML配置文件生成SessionFactory,而后由 SessionFactory 生成Session,最后由Session来开启执行事务和SQL语句。其中 SessionFactoryBuider,SessionFactory,Session的生命周期都是差很少的。

Hibernate和MyBatis都支持JDBC和JTA事务处理。

Mybatis优点

MyBatis能够进行更为细致的SQL优化,能够减小查询字段。

MyBatis容易掌握,而Hibernate门槛较高。

Hibernate优点

Hibernate的DAO层开发比MyBatis简单,Mybatis须要维护SQL和结果映射。

Hibernate对对象的维护和缓存要比MyBatis好,对增删改查的对象的维护要方便。

Hibernate数据库移植性很好,MyBatis的数据库移植性很差,不一样的数据库须要写不一样SQL。

Hibernate有更好的二级缓存机制。Hibernate缓存分为:

一级缓存:session共享(save、update、saveOrupdate、load、get、list) 用于处理当前的单元操做.

二级缓存:sessionFactory共享.(常常读不多被修改,若是使用二级缓存能够提升性能.)

MyBatis自己提供的缓存机制不佳。MyBatis 包含一个很是强大的查询缓存特性,它能够很是方便地配置和定制。默认状况下是没有开启缓存的,除了局部 的 session 缓存,能够加强变现并且处理循环依赖也是必须的。要开启二级缓存,你须要在你的 SQL 映射文件中添加一行:  <cache/>

hibernate中session打开和关闭由sessionFactory的getSession()来管理session的打开和关闭。

第三方缓存实现:cache、Map等;

相关文章
相关标签/搜索