目录
2. 使用SqlSessionFactoryBuilder根据配置文件的字节流创建SqlSessionFactory对象
3. SqlSessionFactory的openSession方法提供SqlSession实例
简述sqlsession查询的运行过程,Executor执行器执行doQuery方法,假设SIMPLE模式
以一个select例子来看源码
package Service;
import Entity.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class UserService {
@Test
public void test() throws IOException {
// 1. 获取配置文件的字节流数据
InputStream inputStream= Resources.getResourceAsStream("mybatis-conf.xml");
// 2. 使用SqlSessionFactoryBuilder根据配置文件的字节流创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
// 3. SqlSessionFactory的openSession方法提供SqlSession实例
SqlSession sqlSession= sqlSessionFactory.openSession();
// 4. SqlSession实例执行数据库操作
List<User> list =sqlSession.selectList("selectAll");
System.out.println(list);
}
}
1. 获取配置文件的字节流数据
InputStream inputStream= Resources.getResourceAsStream("mybatis-conf.xml");
Resources是一个工具类,提供getResourceAsxxx(String)方法,从本地获取指定内容。调Resources.getResourceAsStream("mybatis-conf.xml")获取mybatis-conf.xml的字节流数据,提供相应的重载方法,指定加载mybatis-conf.xml的类加载器。
InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
ClassLoader[] var3 = classLoader;
int var4 = classLoader.length;
// 遍历类加载器
for(int var5 = 0; var5 < var4; ++var5) {
ClassLoader cl = var3[var5];
if (null != cl) {
// 通过类加载器的getResourceAsStream方法读文本的字节流数据
InputStream returnValue = cl.getResourceAsStream(resource);
if (null == returnValue) {
returnValue = cl.getResourceAsStream("/" + resource);
}
// 如果成功获取字节流就返回
if (null != returnValue) {
return returnValue;
}
}
}
return null;
}
2. 使用SqlSessionFactoryBuilder根据配置文件的字节流创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
org.apache.ibatis.session.SqlSessionFactoryBuilder是一个工厂类,提供build方法,通过Reader(字符流)或者InputStream(字节流),用于创建SqlSessionFactory。
//通过mybatis配置文件字节流创建SqlSessionFactory对象(本质是创建SqlSessionFactory的实现类DefaultSqlSessionFactory的对象)
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
SqlSessionFactory var5;
try {
// 通过XMLConfigBuilder解析mybatis配置文件
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
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) {
}
}
return var5;
}
// 通过XMLConfigBuilder解析mybatis配置文件得到的配置信息创建SqlSessionFactory的实现类DefaultSqlSessionFactory的对象
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
3. SqlSessionFactory的openSession方法提供SqlSession实例
SqlSession sqlSession= sqlSessionFactory.openSession();
通过SqlSessionFactoryBuilder实例获取SqlSession实例,在这个期间主要是根据配置文件创建相应的执行器Executor实例。
public SqlSession openSession() {
// 无参的情况下,则使用SqlSessionFactory的configuration创建SqlSession对象
// configuration.getDefaultExecutorType()方法表示获得执行器类型,默认是Simple,执行器有三种Simple,Reuse,Batch三种,如果在全局配置文件中不配置,默认就是Simple
//
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
}
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);
// 使用事务和指定的执行器类型创建一个执行器(最重要,sqlsession就是通过这个executor去操作数据库的)
Executor executor = this.configuration.newExecutor(tx, execType);
// autoCommit是否开启事务自动提交,默认为false禁止事务自动提交。创建SqlSession的实现类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;
}
// 使用事务和指定的执行器类型创建一个执行器
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
// 如果没有指定,默认Simple类型
executorType = executorType == null ? this.defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Object executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
// 我的例子中是默认的Simple类型的,所以我们后面就看一下这个SimpleExecutor类的实例exectuor它是怎么执行数据库操作的
executor = new SimpleExecutor(this, transaction);
}
if (this.cacheEnabled) {
executor = new CachingExecutor((Executor)executor);
}
Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
return executor;
}
4. SqlSession实例执行数据库操作
List<User> list =sqlSession.selectList("selectAll");
// SqlSession接口方法在DefaultSqlSession实现类中实现
// String statement由mapper.xml或者@Select注解提供sql语句节点
// Object parameter可变的参数个数,本质是一个集合,可以通过索引获取其中的参数,也可以通过实参名获取
// RowBounds rowBounds逻辑分页,取offset-limit位置的数据记录,默认offset=0,limit为int的最大值
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
List var5;
try {
// 通过configure对象和java传入参数statement获得一个映射mapper.xml中的statementid或者mapper接口注解的MappedStatement对象
// 注意statement参数是个String对象,内容必须与mapper.xml中的statementid或者接口中注解方法名一致,才能正确映射到该条sql语句
MappedStatement ms = this.configuration.getMappedStatement(statement);
// 执行器调用父类BaseExecutor的query查询方法
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;
}
// ResultHandler resultHandler 对查询得到的结果集ResultSet封装处理返回
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//ms.getBoundSql内部调用RawSqlSource的getBoundSql方法,该方法又调用了StaticSqlSource的getBoundSql方法,并在该方法内部初始化了一个BoundSql对象
BoundSql boundSql = ms.getBoundSql(parameter);
//createCacheKey是调用的BaseExecutor方法根据mappedStatement的id,rowBounds的offset、limit值、要执行的sql语句、传递的参数、environment的id来创建cacheKey。
在query的时候查看是否有cache,如果有则使用cache结果,否则使用内部delegate的query方法,这里跳转到了BaseExecutor的query方法,该方法内部又使用了queryFromDatabase方法。
CacheKey key = this.createCacheKey(ms, parameter, rowBounds, boundSql);
return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
//BaseExecutor的query方法
// MappedStatement ms, 映射sql节点的statement
// Object parameter, 查询条件的参数
// RowBounds rowBounds, 逻辑分页
// ResultHandler resultHandler,
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (this.closed) {
throw new ExecutorException("Executor was closed.");
} else {
if (this.queryStack == 0 && ms.isFlushCacheRequired()) {
this.clearLocalCache();
}
List list;
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 {
--this.queryStack;
}
if (this.queryStack == 0) {
Iterator var8 = this.deferredLoads.iterator();
while(var8.hasNext()) {
BaseExecutor.DeferredLoad deferredLoad = (BaseExecutor.DeferredLoad)var8.next();
deferredLoad.load();
}
this.deferredLoads.clear();
if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
this.clearLocalCache();
}
}
return list;
}
}
// 顾名思义,从数据库中查询,本质是调用deQuery方法
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 {
// doQuery方法在BaseExecutor中是一个抽象方法,在执行器自己的实现类中实现(BatchExecutor\ReuseExectuor\SimpleExecutor, 我的例子中用的SimpleExecutor,所以直接看SimpleExecutor实现的doQuery吧)
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;
}
// SimpleExecutor实现的BaseExecutor的doQuery方法
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
List var9;
try {
// 获取MappedStatement对象的配置信息
Configuration configuration = ms.getConfiguration();
// 创建一个StatementHandler对象,可以认为它是一个Statement执行者,负责JDBC和数据库之间statement的交互
StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 采用的是预编译的方式,根据查询条件,得到sql语句的Statement对象
stmt = this.prepareStatement(handler, ms.getStatementLog());
// Statement执行者执行query方法,执行查询语句,返回查询结果
var9 = handler.query(stmt, resultHandler);
} finally {
this.closeStatement(stmt);
}
return var9;
}
// Executor会执行StatementHandler的prepare()方法进行预编译---->填入connection对象等参数---->再调用parameterize()方法设置参数---->完成预编译
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Connection connection = this.getConnection(statementLog);
Statement stmt = handler.prepare(connection, this.transaction.getTimeout());
handler.parameterize(stmt);
return stmt;
}
// java.sql.PreparedStatement的实现类com.mysql.cj.jdbc.PreparedStatementWrapper类的query方法
// 通过预编译statement执行查询,返回resultSetHandler封装的结果
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement)statement;
ps.execute();
return this.resultSetHandler.handleResultSets(ps);
}
SqlSession四大重要的对象
mybatis本质就是封装了jdbc对数据库的操作,让程序员讲主要精力放在sql上,通过mybatis提供提供的映射方式,自由灵活生成(半个ORM框架,半自动化,sql需要程序员书写)满足业务需求,mybatis将preparedStatement中的输入参数自动进行输入映射,并且将查询结构灵活地映射为java类型。
1. Executor
执行器起到至关重要的作用,它是真正执行Java与数据库交互的东西,参与了整个SQL查询执行过程中。
主要有三种执行器类型-简易执行器SIMPLE(不配置就是默认执行器)、REUSE是一种重用预处理语句、BATCH批量更新、批量专用处理器,分别对应SimpleExecutor、ReuseExecutor、BatchExecutor。
// 通过configure对象的newExxcutor方法,使用事务和执行器类型实例化一个Executor执行器对象
Executor executor = this.configuration.newExecutor(tx, execType);
package org.apache.ibatis.session;
public enum ExecutorType {
SIMPLE,
REUSE,
BATCH;
private ExecutorType() {
}
}
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? this.defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Object 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 (this.cacheEnabled) {
executor = new CachingExecutor((Executor)executor);
}
// 拦截器,configure的属性,在全局配置文件中设置
Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
return executor;
}
2. StatementHanlder
StatementHanlder数据库会话器,主要有三种实现类:SimpleStatementHandler、PrepareStatementHandler、CallableStatementHandler,分别对应Executor的三种执行器(SIMPLE、REUSE、BATCH)
// 创建StatementHandler对象
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null);
// -->调用configure的newStatementHandler方法
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
StatementHandler statementHandler = (StatementHandler)this.interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
// -->根据执行器类型创建相应的StatementHandler对象,并设置拦截器
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
switch(ms.getStatementType()) {
case STATEMENT:
this.delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
this.delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
this.delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}
}
3. ParameterHandler
对预编译中参数进行设置,Executor会执行StatementHandler的prepare()方法进行预编译---->填入connection对象等参数---->再调用parameterize()方法设置参数---->完成预编译
// doUpdate、doQuery等方法中的关键代码
// 通过configure对象创建StatementHandler对象,由这个StatementHandler对象来预编译sql语句并执行数据库操作
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null);
stmt = this.prepareStatement(handler, ms.getStatementLog());
// Executor会执行StatementHandler的prepare()方法进行预编译---->填入connection对象等参数---->再调用parameterize()方法设置参数---->完成预编译
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Connection connection = this.getConnection(statementLog);
Statement stmt = handler.prepare(connection, this.transaction.getTimeout());
handler.parameterize(stmt);
return stmt;
}
// StatementHandler的基本实现类BaseStatementHandler实现prepare方法,只要是调用instantiateStatement方法根据jdbc连接创建statement对象
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(this.boundSql.getSql());
Statement statement = null;
try {
statement = this.instantiateStatement(connection);
this.setStatementTimeout(statement, transactionTimeout);
this.setFetchSize(statement);
return statement;
} catch (SQLException var5) {
this.closeStatement(statement);
throw var5;
} catch (Exception var6) {
this.closeStatement(statement);
throw new ExecutorException("Error preparing statement. Cause: " + var6, var6);
}
}
// 以StatementHandler的实现类SimpleStatementHandler为例
protected Statement instantiateStatement(Connection connection) throws SQLException {
return this.mappedStatement.getResultSetType() == ResultSetType.DEFAULT ? connection.createStatement() : connection.createStatement(this.mappedStatement.getResultSetType().getValue(), 1007);
}
// 调用PreparedStatementHandler的parameterize方法添加参数, 通过DefaultParameterHandler的setParameters方法从ParameterObject中取出参数,交给typeHandler处理
public void parameterize(Statement statement) throws SQLException {
this.parameterHandler.setParameters((PreparedStatement)statement);
}
//调用DefaultParameterHandler的setParameters
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(this.mappedStatement.getParameterMap().getId());
List<ParameterMapping> parameterMappings = this.boundSql.getParameterMappings();
if (parameterMappings != null) {
for(int i = 0; i < parameterMappings.size(); ++i) {
ParameterMapping parameterMapping = (ParameterMapping)parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
String propertyName = parameterMapping.getProperty();
Object value;
if (this.boundSql.hasAdditionalParameter(propertyName)) {
value = this.boundSql.getAdditionalParameter(propertyName);
} else if (this.parameterObject == null) {
value = null;
} else if (this.typeHandlerRegistry.hasTypeHandler(this.parameterObject.getClass())) {
value = this.parameterObject;
} else {
MetaObject metaObject = this.configuration.newMetaObject(this.parameterObject);
value = metaObject.getValue(propertyName);
}
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = this.configuration.getJdbcTypeForNull();
}
try {
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (SQLException | TypeException var10) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + var10, var10);
}
}
}
}
}
4. ResultSetHandler
结果集处理器,对jdbc返回的结果集封装,调用DefaultResultSetHandler的handleCursorResultSets,将查询结果集封装为list+分页等信息返回
// PreparedStatementHandler的query方法
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement)statement;
// 预编译sql并执行
ps.execute();
// resultSetHandler对jdbc返回的结果集封装
return this.resultSetHandler.handleResultSets(ps);
}
// DefaultResultSetHandler的handleCursorResultSets,将查询结果集封装为list+分页等信息返回
public <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling cursor results").object(this.mappedStatement.getId());
ResultSetWrapper rsw = this.getFirstResultSet(stmt);
List<ResultMap> resultMaps = this.mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
this.validateResultMapsCount(rsw, resultMapCount);
if (resultMapCount != 1) {
throw new ExecutorException("Cursor results cannot be mapped to multiple resultMaps");
} else {
ResultMap resultMap = (ResultMap)resultMaps.get(0);
return new DefaultCursor(this, resultMap, rsw, this.rowBounds);
}
}
简述sqlsession查询的运行过程,Executor执行器执行doQuery方法,假设SIMPLE模式
2. 创建StamentHandler数据库会话器执行预编译(调用SimpleExecutor的prepareStatement方法);
2. prepare 方法负责生成 Statement 实例对象(通过SimpleStatementHandler的instantiateStatement方法);
3. parameterize 方法用于处理 Statement 实例多对应的参数(通过DefaultParameterHandler的setParameters方法);
4. StamentHandler数据库会话器执行PreparedStatementHandler的query方法(jdbc的包下的preparedStatement的execute);
5. resultSetHandler返回了封装的结果集(通过DefaultResultSetHandler的handleCursorResultSets方法)