一:配置(约定大于配置)
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:
- configuration(配置)
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
- environment(环境变量)
- databaseIdProvider(数据库厂商标识)
- mappers(映射器)
二. 源码分析
2.1 从调用方法build 对源码理解
step1 : 进入build
step2: 再进入build
step3: 看到SqlSessionFactory
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// 1.SqlSessionFactory传递了一个InputStream,这个InputStream把带有的文件信息,传递给XMLConfigBuilder的对象parser
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
1.SqlSessionFactory传递了一个InputStream,这个InputStream把带有的文件信息,传递给XMLConfigBuilder的对象parser
2.parser调用了parse()方法,来解析xml
step4 进入parse()方法
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
// configuration是xml的跟节点,即在parseConfiguration这个方法中去解析xml
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
1.configuration是xml的跟节点
2.parse() 方法利用parseConfiguration这个方法去解析xml
step 5 进入 parseConfiguration
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
1.根据我们一开始提到的配置顺序来看,可以这个parseConfiguration方法把xml从头到尾的每个节点都拿过来进行解析
2.具体通过
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
来解析整个xml
2.2 从返回对象SqlSessionFactory 对源码进行理解
2.2.1 进入 SqlSessionFactory
SqlSession openSession();
SqlSession openSession(boolean autoCommit);
SqlSession openSession(Connection connection);
SqlSession openSession(TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);
Configuration getConfiguration();
1.进入SqlSessionFactory 这个方法中,看到了一堆的SqlSession,由于SqlSession是接口所以我们要去找他的接口实现类去看源码
2.2.2 找SqlSessionFactory的接口实现类DefaultSqlSessionFactory
1.找到了SqlSessionFactory的接口实现类 DefaultSqlSessionFactory
2.于是我们再返回SqlSessionFactoryBuilder中去查找他SqlSessionFactory的接口实现类DefaultSqlSessionFactory,并且进入其中查看源码
3.通过SqlSessionFactoryBuilder用于返回SqlSessionFactory对象的方法,进入其中找到下面一段代码
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
1.可见其返回的SqlSessionFactory中,new了DefaultSqlSessionFactory这个对象
2.且new 出来的这个DefaultSqlSessionFactory对象里面带有 Configuration 解析的xml文件的内容config,也就是给new出来的DefaultSqlSessionFactory里传了带有xml内容的config。
也就是new DefaultSqlSessionFactory(config);的含义
2.2.3 进入DefaultSqlSessionFactory看他是怎么返回带解析了的xml内容的config
2.2.3.1 进入DefaultSqlSessionFactory之前我们要先看一下 ,我们要获得什么内容
1.由于SqlSession是向数据库去发送指令的
2.明确得到什么,得到的数据用来做什么之后我们再进入DefaultSqlSessionFactory
2.2.3.2 进入DefaultSqlSessionFactory
1.由于我们是为了去得到session对象,所以我们进入openSessionFromDataSource这个方法去看他怎么去得到我们的session对象
2.因为这个方法的返回参数类型是SqlSession,所以我们返回的一定是session对象,于是我们决定进入这个代码
2.2.3.3 进入openSessionFromDataSource方法看他怎么返回session对象
@Override
public Configuration getConfiguration() {
return configuration;
}
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);
//第二步 再看到这个Executor解析器
final Executor executor = configuration.newExecutor(tx, execType);
//第一步.我们通过DefaultSqlSession,知道他得到的对象,在往上看
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();
}
}
1.第一步先查看最终返回值DefaultSqlSession,其中有configuration, executor, autoCommit,根据前面的解释大体知道第一个是xml的什么东西,但是不确定后面的,继续看
2.第二步看到Executor,这个我们知道是解析器,但是不确定这个方法做了什么,返回了什么,所以我们选择进入这个方法
2.2.3.3 进入Executor这个方法,我们查看这个方法做了什么,解析了什么
public interface Executor {
ResultHandler NO_RESULT_HANDLER = null;
int update(MappedStatement ms, Object parameter) throws SQLException;
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
<E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;
List<BatchResult> flushStatements() throws SQLException;
//提交事务
void commit(boolean required) throws SQLException;
//回滚
void rollback(boolean required) throws SQLException;
CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
boolean isCached(MappedStatement ms, CacheKey key);
void clearLocalCache();
void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
Transaction getTransaction();
void close(boolean forceRollback);
boolean isClosed();
void setExecutorWrapper(Executor executor);
}
1.进入Executor这个方法我们发现,这个Executor也是一个接口
2.这个Executor接口提供了,增删改查最基础的方法
3.提交事务
4.回滚事务
5.由于Executor是一个接口,所以我们继续来查找这个Executor接口的实现类
2.2.3.4 查找Executor接口的实现类
1.由于Executor接口的实现类的实现类太多,在这里我们就去看一下他这个简单接口实现类,直接ctrl+n,去看这个实现类SimpleExecutor的源码
2.找到后发现他这里执行两个方法
方法1:douptate
1.发现Statement对象,顿时明白了mybatis底层也是用jdbc来操作数据库的
方法二:doQuery 对象
1.又发现了利用statement对象去返回数据库,确定了mybatis底层肯定是用jdbc去操作数据库的