一.SqlSessionFactory的创建
SqlSessionFactoryBuilder.class
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
SqlSessionFactory var5;
try {
//建立一个配置解析器,用于解析mybatis的配置文件以及mapper配置文件
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//通过解析得到的configuration对象创建一个DefaultSqlSessionFactory对象
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException var13) {
}
}
XmlConfigBuilder.class
//解析xml中的每一个配置信息,并且解析mapper的xml文件
private void parseConfiguration(XNode root) {
try {
this.propertiesElement(root.evalNode("properties"));
Properties settings = this.settingsAsProperties(root.evalNode("settings"));
this.loadCustomVfs(settings);
this.loadCustomLogImpl(settings);
this.typeAliasesElement(root.evalNode("typeAliases"));
this.pluginElement(root.evalNode("plugins"));
this.objectFactoryElement(root.evalNode("objectFactory"));
this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
this.settingsElement(settings);
this.environmentsElement(root.evalNode("environments"));
this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
this.typeHandlerElement(root.evalNode("typeHandlers"));
//解析mapper
this.mapperElement(root.evalNode("mappers"));
} catch (Exception var3) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
}
}
XmlConfigBuilder.class
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
Iterator var2 = parent.getChildren().iterator();
while(true) {
while(var2.hasNext()) {
XNode child = (XNode)var2.next();
String resource;
//若标签为package的解析
if ("package".equals(child.getName())) {
resource = child.getStringAttribute("name");
this.configuration.addMappers(resource);
} else {
//标签为mapper
resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
XMLMapperBuilder mapperParser;
InputStream inputStream;
//对resource进行解析
if (resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
inputStream = Resources.getResourceAsStream(resource);
mapperParser = new XMLMapperBuilder(inputStream, this.configuration, resource, this.configuration.getSqlFragments());
mapperParser.parse();
//对url进行解析
} else if (resource == null && url != null && mapperClass == null) {
.......
} else {
//对class进行解析
if (resource != null || url != null || mapperClass == null) {
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
Class<?> mapperInterface = Resources.classForName(mapperClass);
this.configuration.addMapper(mapperInterface);
}
}
}
进入到mapperParse.parse方法,并深入源码,可以看到
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
Iterator var3 = list.iterator();
while(var3.hasNext()) {
XNode context = (XNode)var3.next();
XMLStatementBuilder statementParser = new XMLStatementBuilder(this.configuration, this.builderAssistant, context, requiredDatabaseId);
try {
//通过此方法会创建Mapper中每个SQL标签的MappedStatement对象
statementParser.parseStatementNode();
} catch (IncompleteElementException var7) {
this.configuration.addIncompleteStatement(statementParser);
}
}
}
回到SqlSessionFactoryBuilder中
//最后通过此方法获取一个DefaultSqlSessionFactory对象
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
二.SqlSession的创建
DefaultSqlSessionFactory.class
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
DefaultSqlSession var8;
try {
//获取数据库配置环境
Environment environment = this.configuration.getEnvironment();
//通过环境获得一个事务工厂
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
//获取一个事务对象
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//通过事务对象和执行器类型获得一个执行器
Executor executor = this.configuration.newExecutor(tx, execType);
//通过配置信息,执行器和是否自动提交这三个信息获得一个DefaultSqlSession
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var12) {
this.closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
注意在创建执行器时或对生成的执行器进行一个装饰,通过装饰模式,将刚才产生的executor 包装成一个更加强大的 executor。
作用:以后 如果我们要给MyBatis写自己的插件, 就可以通过拦截器实现。
插件开发: 1写插件 2放入拦截器
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
。。。。。。。
Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
return executor;
}
三.获取Mapper的代理对象
DefaultSqlSession.class
public <T> T getMapper(Class<T> type) {
return this.configuration.getMapper(type, this);
}
Configuration.class
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return this.mapperRegistry.getMapper(type, sqlSession);
}
MapperRegistry.class
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//通过knownMappers获取一个MapperProxyFactory对象
MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
} else {
try {
//返回一个mapperProxy实例
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}
跟进,可以在MapperProxyFactory.class中获取一个mapperProxy对象
MapperProxyFactory.class
public T newInstance(SqlSession sqlSession) {
MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
return this.newInstance(mapperProxy);
}
从这里可以看到:
(1)先从knownMappers的map集合中获取MapperProxyFactory对象,knownMappers怎么有MapperProxyFactory对象呢?这个是从启动时,扫描出来的,有兴趣的可以看看启动时,扫描mapper。
(2)通过mapperProxyFactory.newInstance(sqlSession);利用了jdk动态代理生成了mapper的代理类MapperProxy
四.执行增删改查
执行增删改查,其实是调用一个MapperProxy(实现了Serializable和InvocationHandle接口)的invoke方法
接下来会调用cachedMapperMethod(method)方法通过Method从缓存中获取一个MapperMethod,如果缓存中没有,则创建一个。接下来会执行这个mapperMethod,参数为sqlsession和args,其中sqlSession存有configuration和executor。进入executor方法中
MapperProxy.class
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
。。。。。。
//先从缓存中获取当前方法的MapperMethod对象,
//缓存中存在则直接获取,没有则创建一个。源码看下方
MapperMethod mapperMethod = this.cachedMapperMethod(method);
//调用mapperMethod的execute方法
return mapperMethod.execute(this.sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
return (MapperMethod)this.methodCache.computeIfAbsent(method, (k) -> {
return new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
});
}
会根据MapperMethod获取sql语句的类型从而进行不同的处理。其中convertArgsToSqlCommandParam(args)会根据args返回一个对象:
如果参数为null,返回一个null;
如果参数个数为1,则返回第一个;
如果参数为多个,则多个参数放入一个Map集合中,并返回。
select方法执行 result = sqlSession.selectOne(this.command.getName(), param);
(此方法在DefaultSqlSession中具体实现)。
MapperMethod.class
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
Object param;
switch(this.command.getType()) {
case INSERT:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
break;
case UPDATE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
break;
case DELETE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
break;
case SELECT:
if (this.method.returnsVoid() && this.method.hasResultHandler()) {
this.executeWithResultHandler(sqlSession, args);
result = null;
} else if (this.method.returnsMany()) {
result = this.executeForMany(sqlSession, args);
} else if (this.method.returnsMap()) {
result = this.executeForMap(sqlSession, args);
} else if (this.method.returnsCursor()) {
result = this.executeForCursor(sqlSession, args);
} else {
//将参数封装成一个Map集合
param = this.method.convertArgsToSqlCommandParam(args);
//执行selectOne方法
result = sqlSession.selectOne(this.command.getName(), param);
if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + this.command.getName());
}
if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
} else {
return result;
}
}
这里的sql语句是select,跟进selectOne方法
DefaultSqlSession.class
public <T> T selectOne(String statement, Object parameter) {
//不管是查询一个还是查询多个都会进入selectList中
List<T> list = this.selectList(statement, parameter);
if (list.size() == 1) {
//根据最终返回的一个List集合获取一个数据
return list.get(0);
//如果数据大于一个会报错,因为这里是selectOne
} else if (list.size() > 1) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return null;
}
}
进入selectList方法中
DefaultSqlSession.class
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
List var5;
try {
//会根据传入的statement(此参数通过MapperMethod.getName()获取),
//从configuration中获取MappedStatement
MappedStatement ms = this.configuration.getMappedStatement(statement);
//执行器进行查询(CachingExecutor)
var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception var9) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + var9, var9);
} finally {
ErrorContext.instance().reset();
}
return var5;
}.
进入query(位于CachingExecutor.class)中
CachingExecutor.class
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//boundSql :将我们写的SQL 和 参数值进行了拼接后的对象,即最终能被真正执行的SQL
BoundSql boundSql = ms.getBoundSql(parameterObject);
//生成一个缓存
CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql);
//继续进行查询
return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
CachingExecutor.class
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
Cache cache = ms.getCache();
//如果缓存不为空,则直接获取
if (cache != null) {
this.flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
this.ensureNoOutParams(ms, boundSql);
List<E> list = (List)this.tcm.getObject(cache, key);
if (list == null) {
list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
this.tcm.putObject(cache, key, list);
}
return list;
}
}
//继续进行查询(此方法位于BaseExecutor.class中)
return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
获取缓存,如果缓存存在,直接获取;否则,通过delegate.query()创建。(方法位于BaseExecutor.class中)
BaseExecutor.class
try{
++this.queryStack;
list = resultHandler == null ? (List)this.localCache.getObject(key) : null;
if (list != null) {
//直接从缓存中获取
this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
//通过从数据库中查找
list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
}finally
先从本地缓存中获取,如果没有则调用queryFromDatabase()方法从数据库查找
BaseExecutor.class
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
//设置缓存
this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);
List list;
try {
//进入此方法,此方法由SimpleExecutor实现
list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
this.localCache.removeObject(key);
}
this.localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
this.localOutputParameterCache.putObject(key, parameter);
}
return list;
}
进入doQuery()方法(此方法在SimpleExecutor.class中)
mybatis使用的jdbc对象是PreparedStatement
SimpleExecutor.class
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
List var9;
try {
Configuration configuration = ms.getConfiguration();
//会通过我们传入的参数创建一个StatementHandler对象,并且
//会通过interceptorChain进行装饰并返回一个增强的StatementHandler
//PrepareStatementHandler.class
StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
//获取一个Statement对象
stmt = this.prepareStatement(handler, ms.getStatementLog());
//通过获取的Statement进行查询
var9 = handler.query(stmt, resultHandler);
} finally {
this.closeStatement(stmt);
}
return var9;
}
进入prepareStatement()方法
SimpleExecutor.class
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Connection connection = this.getConnection(statementLog);
//通过PrepareStatementHandler的prepare方法创建一个statement
Statement stmt = handler.prepare(connection, this.transaction.getTimeout());
//会将一个Statement转为PreparedStatement
//在PrepareStatementHandler中进行,
//涉及ParameterHandler.class,处理参数的控制器
handler.parameterize(stmt);
return stmt;
}
PrepareStatementHandler.class
public void parameterize(Statement statement) throws SQLException {
this.parameterHandler.setParameters((PreparedStatement)statement);
}
进入handler.query(stmt, resultHandler);方法获得List结果集
PrepareStatementHandler.class
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement)statement;
ps.execute();
//resultSetHandler,处理结果集的控制器
return this.resultSetHandler.handleResultSets(ps);
}