MyBatis 原理浅析——基本原理

前言

MyBatis 是一个被普遍应用的持久化框架。一个简单的使用示例以下所示,先建立会话工厂,而后从会话工厂中打开会话,经过 class 类型和配置生成 Mapper 接口的代理实现,最后使用 Mapper 进行持久化操做。 java

本文将从 MyBatis 中的 SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession 和 Mapper 几个方面入手简单分析 MyBatis 的实现原理。在后面的系列文章中会进一步具体分析核心类的细节实现。程序员

 

SqlSessionFactoryBuilder

SqlSessionFactoryBuilder 使用 Builder 模式去生成 SqlSessionFactory,所以只提供了多个 build 方法。这些方法能够接受 XML 配置文件的 Reader 或 InputStream 输入流,也能够传入 environment 指定环境或传入 Properties 做为属性。sql

 在 build 方法的实现中,首先根据传入的输入流、environment 和 Properties 构建 XMLConfigBuilder 对象,而后调用其 parse() 方法解析 XML 文件获得 Configuration 对象,最后建立 SqlSessionFactory 对象并返回。数据库

 

SqlSessionFactory

SqlSessionFactory 是一个工厂接口,默认实现是 DefaultSqlSessionFactory。SqlSessionFactory 的做用是获取 SqlSession,所以提供了多个 openSession 方法,支持从 DataSource 数据源和一个给定的链接 Connection 中建立 SqlSession。缓存

 openSession 方法的底层实现能够分为 5 步:微信

①从 Configuration 对象中获取环境配置 Environment;session

②根据环境配置获得事务工厂 TransactionFactory;app

③从事务工厂获得事务 Transaction,Transaction 包装了数据库链接,处理数据库链接的建立、准备、提交、回滚和关闭;框架

④建立执行器 Executor;分布式

⑤建立 SqlSession,返回 DefaultSqlSession 的实例。

其中从 DataSource 数据源建立 SqlSession 的过程以下所示:

Java代码   收藏代码
  1. Transaction tx =null;  
  2. try{  
  3. finalEnvironment environment = configuration.getEnvironment();  
  4. finalTransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);  
  5. tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);  
  6. finalExecutor executor = configuration.newExecutor(tx, execType);  
  7. returnnewDefaultSqlSession(configuration, executor, autoCommit);  
  8. }catch(Exception e){  
  9. closeTransaction(tx);// may have fetched a connection so lets call close()  
  10. throwExceptionFactory.wrapException("Error opening session. Cause: "+ e, e);  
  11. }finally{  
  12. ErrorContext.instance().reset();  
  13. }  

 

 

SqlSession

SqlSession 是一个接口,默认实现是 DefaultSqlSession,提供了多种数据库操做方式,如 select、selectOne、selectList、insert、update、delete、commit、rollback 和 getMapper 等方法。getMapper 方法用于获取 Mapper 接口的代理实现。在 MyBatis 中建议使用 Mapper 接口操做数据库。

 数据库的增删改查和事务的提交回滚都是经过 Executor 执行的。Executor 有 3 种类型 SIMPLE、REUSE、BATCH,默认使用简易执行器 SIMPLE,REUSE 类型执行器重用预处理语句,BATCH 类型执行器重用预处理语句和批量更新。Executor 对象的建立在 Configuration 类型的 newExecutor 方法中进行。

 Executor 在执行过程当中,会用到 StatementHandler、ParameterHandler 和 ResultHandler,其中 StatementHandler 封装了 java.sql.Statement 的相关操做,ParameterHandler 封装了 SQL 对参数的处理,ResultHandler 封装了对返回数据集的处理。Executor 的执行过程,就是对这 3 个对象的调度过程。更多分析在后续文章中进行。

 

Mapper

Mapper 是经过 JDK 动态代理实现的,在 MapperProxyFactory 中建立 MapperProxy 并进行接口代理封装。对 Mapper 接口的调用其实是由 MapperProxy 实现的。

Java代码   收藏代码
  1. @SuppressWarnings("unchecked")  
  2. protected T newInstance(MapperProxy<T> mapperProxy){  
  3. return(T)Proxy.newProxyInstance(mapperInterface.getClassLoader(),newClass[]{ mapperInterface }, mapperProxy);  
  4. }  
  5.    
  6. public T newInstance(SqlSession sqlSession){  
  7. finalMapperProxy<T> mapperProxy =newMapperProxy<T>(sqlSession, mapperInterface, methodCache);  
  8. return newInstance(mapperProxy);  

在 MapperProxy 中,实现了 InvocationHandler 的 invoke 方法。methodCache 是一个 ConcurrentHashMap,其中存储了方法与 MapperMethod 的对应关系。从 methodCache 缓存中获取或建立 MapperMethod 对象,而后调用 MapperMethod 对象的 execute 方法执行数据库操做。

Java代码   收藏代码
  1. @Override  
  2. publicObject invoke(Object proxy,Method method,Object[] args)throwsThrowable{  
  3. try{  
  4. if(Object.class.equals(method.getDeclaringClass())){  
  5. return method.invoke(this, args);  
  6. }elseif(isDefaultMethod(method)){  
  7. return invokeDefaultMethod(proxy, method, args);  
  8. }  
  9. }catch(Throwable t){  
  10. throwExceptionUtil.unwrapThrowable(t);  
  11. }  
  12. finalMapperMethod mapperMethod = cachedMapperMethod(method);  
  13. return mapperMethod.execute(sqlSession, args);  
  14. }  
  15.    
  16. privateMapperMethod cachedMapperMethod(Method method){  
  17. MapperMethod mapperMethod = methodCache.get(method);  
  18. if(mapperMethod ==null){  
  19. mapperMethod =newMapperMethod(mapperInterface, method, sqlSession.getConfiguration());  
  20. methodCache.put(method, mapperMethod);  
  21. }  
  22. return mapperMethod;  

建立 MapperMethod 对象时,会在构造函数中初始化 SqlCommand 和MethodSignature。SqlCommand 包含了数据库操做的名称,格式为 “接口名.操做名称”,以及 XML 中配置的操做类型,如 select、update等,把一个 Mapper 接口与 XML中的一个配置结合起来。MethodSignature 是方法的签名,标记了方法的返回值类型,对于使用 RowBounds(offset 和 limit 配置)、ResultHandler(结果处理回调)做为参数的方法记录参数位置并初始化参数处理器。

在 MapperMethod 的 execute 方法中,根据 SqlCommand 中的配置选择 SqlSession 的方法,根据 MethodSignature 的配置处理传入的参数,调用 SqlSession 的方法进行数据库操做,最后根据 MethodSignature 的返回值类型返回操做结果。

每周 3 篇学习笔记或技术总结,面向有必定基础的 Java 程序员,内容涉及 Java 进阶、虚拟机、MySQL、NoSQL、分布式计算、开源框架等多个领域。关注做者或微信公众号 backend-develop 第一时间获取最新内容。

MyBatis 原理浅析--基本原理
相关文章
相关标签/搜索