介绍哦
Mybatis十分重要的持久层框架,半Orm的代表人物,驰名中外,无敌哦。
文章立志于解析源码,弄懂原理。表述不好,还请见谅。
加载流程
Mybatis加载配置可以使用Xml配置或者代码配置。
结构👇
一个标准的Mybatis配置需要一个环境和可用的映射文件,而一个Mybatis环境需要一个数据源和一个事务的实例。
//datasource
DataSource dataSource = new PooledDataSource("Driver", "url", "username", "password");
//transaction
TransactionFactory transactionFactory = new JdbcTransactionFactory();
//env
Environment environment = new Environment("development", transactionFactory, dataSource);
//config
Configuration configuration = new Configuration(environment);
configuration.addMappers("mappers");
//builder
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(configuration);
Datasource
mybatis提供了三种DataSource方式。
突出一个见名知意 。
当然也可以使用第三方或者自行实现,这里主要突出原理,连接池是Env的一个属性。
Transaction
同样Mybatis提供了两种Transaction的实现方式。
第一个很好理解依赖于JDBC链接的事务处理方案。
第二个ManagedTransaction目的是使事务管理依赖于容器操作,在这个类中的commit()和roolback()方法均为空方法,即不操作事务。那么事务的操作就由其他容器操作。
addMapper
添加映射,添加映射有很多重载方法:
public <T> void addMapper(Class<T> type)
public void addMappers(String packageName)
等...
以类的形式添加映射其本质是向Configration.mapperRegistry这个属性中添加类,这个类会创建MapperAnnotationBuilder解析类上的每一个方法的注解。
在MapperAnnotationBuilder类的parse()方法中会首先根据类的名称去查找同名的.xml文件,如果找到了则创建XMLMapperBuilder去解析Xml文件。
无论是MapperAnnotationBuilder还是XMLMapperBuilder最终都会调用Configuration.addMappedStatement()方法添加回Configuration中。
Configuration中维护着一个Map属性mappedStatements
然而在Xml的配置方式中存在直接添加XMl.statement的方式。在XMLConfigBuilder会解析XMl其中就会创建XMLMapperBuilder解析<mapper/>节点最终也会添加到Configuration中
SqlSessionFactory
在调用builder方法后就会返回一个DefaultSqlSessionFactory
SqlSession
SqlSession是Mybatis的实际业务执行器,在调用factory.openSession()时做了如下操作
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
这里创建了两个东西,一个是Transaction一个是Executor,一个管理事务,一个处理Sql运行逻辑.
在configuration.newExecutor()方法中
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
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);
}
//添加插件
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
会根据执行模式创建对应的执行器,以及判断是否开启缓存,以及以代理的形式添加插件。 这里的三个模式分别是:
- SIMPLE: 这个执行器类型不做特殊的事情。它为每个语句的执行创建一个新的预处理语句。(默认)
- REUSE: 这个执行器类型会复用预处理语句。
- BATCH: 这个执行器会批量执行所有更新语句,如果 SELECT 在它们中间执行还会标定它们是必须的,来保证一个简单并易于理解的行为。