MyBatis源码阅读-总索引
MyBatis有两种方式执行SQL,第一种是调用SqlSession的相关方法去执行,第二种是通过SqlSession获取Mapper接口,通过动态代理,其最终也是调用SqlSession的相关方法去执行,但是第二种方法比较常用而且更加方便。本问主要讲解使用第二种方式执行的流程。
//1.获取配置文件的输入流
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//2.通过SqlSessionFactoryBuilder获取SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
查看build()方法
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
SqlSessionFactory var5;
try {
//通过输入流构建XMLConfigBuilder对象
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
//parser.parse()返回的是Configuration类型对象
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException var13) {
;
}
}
return var5;
}
查看parser.parse()方法
public Configuration parse() {
if (this.parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
} else {
this.parsed = true;
this.parseConfiguration(this.parser.evalNode("/configuration"));
return this.configuration;
}
}
//解析配置文件节点
private void parseConfiguration(XNode root) {
try {
this.propertiesElement(root.evalNode("properties"));
Properties settings = this.settingsAsProperties(root.evalNode("settings"));
this.loadCustomVfs(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"));
this.mapperElement(root.evalNode("mappers"));
} catch (Exception var3) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
}
}
利用Configuration对象创建DefaultSqlSessionFactory对象
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
从上面可以看出:获取SqlSessionFactory的流程是:
1.使用Resources类将配置文件转换成输入流
2.通过SqlSessionFactoryBuilder.build(Reader reader, String environment, Properties properties)构建
3.通过输入流创建XMLConfigBuilder对象,并使用XMLConfigBuilder.parse()方法将输入流转换为Configuration对象
4.利用Configuration对象创建DefaultSqlSessionFactory对象
SqlSession sqlSession = SqlSessionFactory.openSession();
openSession 最终调用的是openSessionFromDataSource方法。
有两种方式,第一种是从dataSource,第二种是从Connection连接来创建。
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
DefaultSqlSession var8;
try {
//获取Environment对象,包括environment id,DataSource , 事物工厂
Environment environment = this.configuration.getEnvironment();
//通过事务工厂获取事务
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//创建执行器Executor
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;
}
private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
DefaultSqlSession var8;
try {
boolean autoCommit;
try {
autoCommit = connection.getAutoCommit();
} catch (SQLException var13) {
autoCommit = true;
}
Environment environment = this.configuration.getEnvironment();
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
Transaction tx = transactionFactory.newTransaction(connection);
Executor executor = this.configuration.newExecutor(tx, execType);
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var14, var14);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
从上面可以看,通过SqlSessionFactory获取SqlSession的流程是:
1.通过configuration对象获取Environment对象,包括environment id,DataSource , 事物工厂
2.通过事务工厂获取事务
3.创建执行器Executor
4.创建DefaultSqlSession对象。
调用SqlSession的getMapper方法获取,其调用的Configuration类的getMapper()方法
这里的type为需要获取的mapper接口。
public <T> T getMapper(Class<T> type) {
return this.configuration.getMapper(type, this);
}
来看Configuration类的getMapper()方法,其调用的是mapperRegistry类的getMapper方法,参数是接口和当前的sqlSession。
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return this.mapperRegistry.getMapper(type, sqlSession);
}
MapperRegistry类的getMapper方法,这里先获取一个MapperProxyFactory对象,并通过MapperProxyFactory的newInstance来创建Mapper对象。
knownMappers是一个MapperProxyFactory的HashMap对象。
相关的MapperProxyFactory对象是在解析配置文件并初始化时创建并添加进去的。
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
} else {
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}
继续查看MapperProxyFactory类的newInstance方法
public T newInstance(SqlSession sqlSession) {
MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
return this.newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}
到这里为止,就创建了mapper接口的动态代理对象,而被代理的方法被放到MapperProxy类中。因此获取Mapper对象就是一个创建其动态代理的过程。
上一节说明了如何创建mapper接口的动态代理对象,接下来讲解使用该动态代理对象执行Sql 的流程。
创建好mapper对象后,使用很简单,直接只用该对象调用接口内的相关方法即可。
sysUserMapper = sqlSession1.getMapper(SysUserMapper.class);
sysUser1 = sysUserMapper.selectByPrimaryKey(1030L);
看一下执行时的调用栈
1.调用方法selectByPrimaryKey
2.调用MapperProxy类的invoke方法
3.调用MapperMethod类的execute方法,并返回结果
4.调用DefaultSqlSession(SqlSession的子类)的selectOne,最终调用的是selectList方法
5.selectList方法中通过执行器executor去执行Sql语句,并返回结果,由于使用了缓存,因此这里的执行器是CachingExecutor。
org.apache.ibatis.binding.MapperProxy
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
if (this.isDefaultMethod(method)) {
return this.invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
MapperMethod mapperMethod = this.cachedMapperMethod(method);
return mapperMethod.execute(this.sqlSession, args);
}
上一节提到mapper被代理的方法被放到MapperProxy类中,因此调用mapper方法后,将会调用MapperProxy类的invoke方法。
这是传入invoke方法的参数
之后调用MapperMethod类的execute方法
MapperMethod mapperMethod = this.cachedMapperMethod(method);
return mapperMethod.execute(this.sqlSession, args);
org.apache.ibatis.binding.MapperMethod
public Object execute(SqlSession sqlSession, Object[] args) {
Object param;
Object result;
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 {
param = this.method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(this.command.getName(), param);
}
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;
}
}
这里采用命令模式,根据mapper配置文件和传入的接口名称和方法,获取当前执行的sql是什么操作。可以看到,不管是什么操作,其最终都是调用SqlSession中的相关方法。
所以使用SqlSession方式或者通过mapper方式去执行,最终都是执行SqlSession中的方法,只是使用mapper方式更加简单。
不管是update或者insert等操作,都是使用执行器去执行.
Executor接口:
public interface Executor {
ResultHandler NO_RESULT_HANDLER = null;
int update(MappedStatement var1, Object var2) throws SQLException;
<E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4, CacheKey var5, BoundSql var6) throws SQLException;
<E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4) throws SQLException;
<E> Cursor<E> queryCursor(MappedStatement var1, Object var2, RowBounds var3) throws SQLException;
List<BatchResult> flushStatements() throws SQLException;
void commit(boolean var1) throws SQLException;
void rollback(boolean var1) throws SQLException;
CacheKey createCacheKey(MappedStatement var1, Object var2, RowBounds var3, BoundSql var4);
boolean isCached(MappedStatement var1, CacheKey var2);
void clearLocalCache();
void deferLoad(MappedStatement var1, MetaObject var2, String var3, CacheKey var4, Class<?> var5);
Transaction getTransaction();
void close(boolean var1);
boolean isClosed();
void setExecutorWrapper(Executor var1);
}
DefaultSqlSession类:
//select最终调用
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
List var5;
try {
MappedStatement ms = this.configuration.getMappedStatement(statement);
//使用执行器
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;
}
//delete,update ,insert 最终调用
public int update(String statement, Object parameter) {
int var4;
try {
this.dirty = true;
MappedStatement ms = this.configuration.getMappedStatement(statement);
//使用执行器
var4 = this.executor.update(ms, this.wrapCollection(parameter));
} catch (Exception var8) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + var8, var8);
} finally {
ErrorContext.instance().reset();
}
return var4;
}
到此,整个执行流程讲解完。