原文日期:2018-02-08
mybatis框架是一个半自动ORM框架,并且它是目前主流框架套件(SSM)之一,相比Hibernate来说,它是非常简单且容易上手。虽说hibernate声称自己不需要写sql,并且可以跨数据库。但是对于程序员的我们来说,多写写sql还是有好处的,而且哪个公司闲着没事随便换数据库。目前工作中使用mybatis的频率比较高,因此打算对mybatis知识进行一次整理。
mybatis版本
3.4.5
mybatis问题
-
mybatis xml配置文件处理?
xml配置文件解析入口类是XMLConfigBuilder,它只提供一个parse公有方法,parse方法调用parseConfiguration方法,在该方法中会对配置文件的各个元素节点进行解析,最后将值设置到Configuration等实例中。 mybatis使用jdk xpath方式解析xml配置文件,mybatis入口类是XPathParser。XPathParser内有一个Document对象和XPath解析对象,通过XPath将对应节点解析成Node,然后将Node封装成mybatis的XNode对象。XNode提供了一系列访问xml元素属性、内容、子节点的接口。
XMLConfigBuilder->XPathParser->XNode->Node(W3c node解析) -
mapper xml process?
mapper xml文件解析入口类是XMLMapperBuilder,它同样提供了一个parse公有方法去解析,它解析xml方式和配置文件的解析一样,都是使用XNode访问xml元素。主要解析cache、parameterMap、resultMap、sql、select、insert、update、delete节点。其中select|insert|update|delete都交由XMLStatementBuilder解析,每个节点对应一个MappedStatement实例。MappedStatement表示一个完整的sql块,它包含sql命令类型、sql源、参数类型、结果集映射、缓存等信息。一般实现自定义分页插件时,可以构造一个MappedStatement去查询总记录数。 -
SqlSessionFactory生成?
在解析完xml配置文件和mapper文件后,并将对应配置信息设入Configuration对象中。之后直接创建DefaultSqlSessionFactory实例,并将Configuration对象当做实例变量置入,以便后续直接使用。 -
SqlSession生成?
SqlSessionFactory作为SqlSession的工厂类,专门用来生成SqlSession实例。工厂类首先从配置文件中获取配置的事务管理器,默认是JdbcTransactionManager,并从事务管理器中获得一个事务,之后将事务包装成Excutor,最后传给DefaulSqlSession类,并实例化。 -
SqlSession commit 和 rollback?
SqlSession的commit和rollback操作会先调用Executor的commit和rollback方法。Executor首先会做一些清理工作(清理本地缓存),然后再执行commit或者rollback操作。 -
Transaction process?
mybatis提供了两个事务实现,分别是JdbcTransaction和ManagedTransaction。JdbcTransaction是直接使用jdbc的提交和回滚,依赖于从数据源获取的连接来管理事务;ManagedTransaction事务交由容器来管理(比如tomcat、jetty),并且他的的commit和rollback方法都是空实现。 -
plugin?
mybatis的插件机制是由jdk的动态代理实现,只提供了四个接口可以被代理:ParameterHandler、StatementHandler、ResultSetHandler和Executor,它们分别是处理参数、处理sql、处理结果集、执行器。即我们可以自定义处理参数逻辑、自定义处理sql、自定义处理执行结果、自定义执行过程。
mybatis提供了插件链InterceptorChain类,去存储所有的插件Interceptor。将插件注入到这些接口的入口是Configuration的newParameterHandler、newResultSetHandler、newStatementHandler、newExecutor,它们都调用了InterceptorChain的pluginAll去将插件注入到对应处理实例中。 mybatis还提供了Plugin类,封装了动态代理目标对象,以便支持插件功能。 -
exception process?
mybatis定义了PersistenceException异常基类,并且在每个包(模块)中都定义了对应的异常,它们都是PersistenceException的子类。同时mybatis提供了ExceptionFactory工厂类,该类只有一个公有静态方法wrapException,它的作用是将各种异常包装统一包装成PersistenceException实例。 -
logging process?
mybatis提供了统一的Log日志接口,并且支持四种日志级别(error、debug、trace、warn),通过适配器模式去适配目前市面上大部分主流的日志框架。其实现原理是在应用启动时去加载各个日志框架的实现类,如果加载成功,则表示使用该日志框架,其加载顺序是slf4j->commonslogging->log4j2->log4j->jdklog->nolog。入口类LogFactory。
有了日志工厂类,mybatis对jdbc的Connection、Statement、PreparedStatement、ResultSet接口进行动态代理,并为它们增加日志记录功能。详见代理实现类是ConnectionLogger、StatementLogger、PreparedStatementLogger、ResultSetLogger。 -
annotation?
在配置了扫描mapperClass类或者package时,mybatis会去扫描对应java类或者package,然后调用XMLAnnotationBuilder去扫描对应的Mapper类并解析。调用入口是XMLConfigBuilder的mapperElement方法,主要通过反射获取注解及注解上的信息。比如Select注解(它的value值就是sql),mybatis会将sql值解析到MappedStatement对象中。 -
cache module?
mybatis提供了Cache接口去实现缓存,并且提供了一个默认缓存实现PerpetualCache,它内部使用一个map变量去缓存数据。不仅如此,mybatis还提供了CacheKey去支持缓存key的实现。根据缓存的特性,mybatis还提供了一系列装饰器Cache实现类去加强Cache的功能,这些类都在decorators包中,比如LruCache、FifoCache、BlockingCache等(从名字上可以知道他们的作用)。
再有了缓存实现的类的情况下,mybatis支持两个纬度的缓存,一个是SqlSession级别,另一个是SqlSessionFactory级别。分别表示同一个SqlSession下的相同MappedStatement和参数执行多次,实际只会执行一条sql;同一个SqlSessionFactory下的相同MappedStatement和参数执行多次,最终只会执行一条sql。
mybatis例子
// 指定MyBatis配置文件
String configFile = "mybatis-config.xml";
// 1、指定MyBaties配置文件
InputStream inputStream = Resources.getResourceAsStream(configFile);
// 2、创建SqlSessionFactory()
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = null;
try {
// 3、获取SqlSession
session = sessionFactory.openSession();
// 4、获取DAO接口对象
UserMapper userMapper = session.getMapper(UserMapper.class);
// 5、CRUD操作
// 5.1--查询
User user = userMapper.getUserById(1);
session.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 6、关闭SqlSession
if (session != null) {
session.close();
}
}
mybatis处理流程
- SqlSessionFactoryBuilder创建SqlSessionFactory实例。
- SqlSessionFactoryBuilder委派XMLConfigBuilder类去解析mybatis-config.xml文件,并组装成Configuration实例。
- XMLConfigBuilder将xml文件流委托给XPathParser类去解析成XNode节点。XPathParser通过java自带的jaxp方式将xml解析成Node,然后将Node包装成XNode,方便XMLConfigBuilder解析。
- XMLConfigBuilder针对XNode节点,解析对应xml节点属性。如plugins节点解析成Interceptor拦截器集合;environments节点解析成Environment对象,等。
- 将Configuration实例交由DefaultSqlSessionFactory类,并将DefaultSqlSessionFactory实例化返回。
- SqlSessionFactoryBuilder委派XMLConfigBuilder类去解析mybatis-config.xml文件,并组装成Configuration实例。
- SqlSessionFactory创建SqlSession实例。
- 从Configuration中获取Enviroment对象,再从Enviroment对象中获取事务工厂类TransactionFactory对应的实例对象。
- TransactionFactory事务工厂类创建一个Transaction对象。
- 通过ExecutorType类型创建与其对应的Executor执行器,该执行器会将事务对象包装起来。默认创建SimpleExecutor执行器。
- 将Configuration和Executor实例包装成SqlSession对象返回。
可以看出,实际执行数据库操作的是Executor对象,而事务由Transaction控制。
- SqlSession执行数据库操作(insert、delete、update、select等)。
- 通过id(mapper.xml文件的命名空间+sql语句的id)查找MappedStatement实例(已将sql包装起来)。
- 将MappedStatement实例和方法入参交由Executor实例执行,返回结果。
SqlSession执行数据库操作有两种方式,一种是通过mapper.xml的id直接访问,另一种是通过面向Mapper接口方式调用。Mapper接口方式首先会返回一个代理MapperProxy,实际执行方法时,通过接口的完全限定名+方法名称作为id调用SqlSession的方法,即上述步骤。这也就是为什么mapper.xml的命名空间和sql语句id要与Mapper接口的完全限定名和方法名各自对应
- SqlSession commit/rollback事务。
mybatis的事务处理最终依然是调用jdbc Connection的commit和rollback两个方法进行提交和回滚操作。它的调用路线如下:
sqlSession.commit/rollback->executor.commit/rollback->transaction.commit/rollback->connection->commit->rollback
总结
百度脑图:技术学习整理路线 mybatis知识块。