SQL执行流程
MyBatis总是通过SqlSessionFactoryBuilder创建SqlSessionFactory,然后用SqlSessionFactory创建SqlSession,再用SqlSession获取Mapper接口来进行SQL操作。
通过SqlSession.getMapper -> this.configuration.getMapper(type, this) -> this.mapperRegistry.getMapper(type, sqlSession) -> mapperProxyFactory.newInstance(sqlSession) -> Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{ this.mapperInterface}, mapperProxy)获得了一个Mapper接口类型的反射代理类。其中MapperProxy类用来处理Mapper接口函数的请求:
1 |
|
最终请求被转回SqlSession进行处理,而SqlSession底层都是依赖Executor类进行SQL操作。Executor依赖Transaction进行getConnection(持有DataSource进行连续获取MyBatis(2)-连接管理)、commit、rollback、close等事务控制,如果是JdbcTransaction则直接依赖java.sql.Connection的方法。Executor同时依赖StatementHandler调用java.sql.Statement进行SQL执行。
1 |
|
缓存管理
一级缓存
默认值为SESSION,这种情况下会缓存一个会话中执行的所有查询。若设置值为STATEMENT,本地会话仅用在语句执行上,对相同SqlSession的不同调用将不会共享数据。若设置为SESSION,同一个session内的insert/delete/update操作会令缓存失效,但另外一个session的insert/delete/update操作不会,所以会一起脏读,建议设置为STATEMENT。缓存存在BaseExecutor中PerpetualCache的HashMap里。
1 |
|
二级缓存
利用cacheEnabled全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存,默认为true。由CachingExecutor装饰某一个其他的BaseExecutor来实现,可以在SqlSession之间共享缓存数据,但要commit之后才能生效。由于缓存是以Mapper名区分存储的,一个Mapper的更新操作不会去刷新另一个Mapper的缓存,所以多表查询时会出现脏读。
1 |
|