上一篇中已经解析了配置文件,并创建了DefaultSqlSessionFactory对象,现在来看一下从DefaultSqlSessionFactory对象中创建一个sqlSession并执行一次insert操作的过程。(MyBatis版本:3.2)
首先是获取SqlSession的过程:
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
private final TransactionFactory managedTransactionFactory;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
this.managedTransactionFactory = new ManagedTransactionFactory();
}
public SqlSession openSession() {
//defaultExecutorType = ExecutorType.SIMPLE
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
try {
//从environment中获取dataSource和transactionFactory
final Environment environment = configuration.getEnvironment();
final DataSource dataSource = getDataSourceFromEnvironment(environment);
TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
Connection connection = dataSource.getConnection();
if (level != null) {
connection.setTransactionIsolation(level.getLevel());
}
//如果日志设置到debug级别,则为connection设置代理,并对Statement,PrepareStatement,ResultSet对象设置代理,主要作用也就是获取更多的调试信息,打印更详细的log。
connection = wrapConnection(connection);
Transaction tx = transactionFactory.newTransaction(connection, autoCommit);
Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (SQLException e) {
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//从environment中获取dataSource和transactionFactory
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//此处返回SimpleExecutor, executor是sql语句执行的关键。
final Executor executor = configuration.newExecutor(tx, execType, autoCommit);
//将生成的executor赋值给sqlSession
return new DefaultSqlSession(configuration, executor);
} 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();
}
}
}
看一下executor的生成过程:
public class Configuration {
//ExecutorType用的是默认的,ExecutorType.SIMPLE
public Executor newExecutor(Transaction transaction, ExecutorType executorType, boolean autoCommit) {
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);
}
//如果使用cache,CachingExeutor对真正的executor做了简单的封装。
if (cacheEnabled) {
executor = new CachingExecutor(executor, autoCommit);
}
//这里将executor添加到拦截器链中
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
}
public class InterceptorChain {
private final List<Interceptor> interceptors = new ArrayList<Interceptor>();
//该方法中拦截器对executor做了代理,然后后续的拦截器对面前的拦截器做代理。
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
public void addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
}
}
//MyBatis并没有官方的拦截器,所以无法看到在plugin方法中官方是怎么做的,通常在此方法中会调用Plugin.wrap()方法。
public class Plugin implements InvocationHandler {
private Object target;
private Interceptor interceptor;
private Map<Class<?>, Set<Method>> signatureMap;
private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) {
this.target = target;
this.interceptor = interceptor;
this.signatureMap = signatureMap;
}
//这里第一个参数是被代理的对象,第二个参数是代理对象。
//最开始的被代理对象是executor,被拦截器代理,然后拦截器本身也会变成被代理的对象,被后面的拦截器代理
public static Object wrap(Object target, Interceptor interceptor) {
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
Class<?> type = target.getClass();
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
//这里是真正设置代理的地方
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
Set<Method> methods = signatureMap.get(method.getDeclaringClass());
if (methods != null && methods.contains(method)) {
//intercept()方法是代理逻辑具体执行的地方,在被代理对象的method执行前后,或者围绕着被代理对象的method的执行过程,做一些事情。
return interceptor.intercept(new Invocation(target, method, args));
}
return method.invoke(target, args);
} catch (Exception e) {
throw ExceptionUtil.unwrapThrowable(e);
}
}
}
//至此,SqlSession创建过程结束。
下面看一下SqlSesssion执行insert操作的过程:
public class DefaultSqlSession implements SqlSession {
private Configuration configuration;
private Executor executor;
private boolean dirty;
public DefaultSqlSession(Configuration configuration, Executor executor) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
}
public int insert(String statement, Object parameter) {
return update(statement, parameter);
}
public int update(String statement, Object parameter) {
try {
dirty = true;
//此时获取MappedStatement的时候,如果还有未解析的resultMap,parameterMap或者cache,则继续解析。
MappedStatement ms = configuration.getMappedStatement(statement);
//如果调用的statement使用了cache,那么会先清除所有cache,然后再交给SimpleExecutor去处理(Executor默认类型是SimpleExecutor)。
//一个mapper文件中如果声明了cache,那么select操作默认会使用这个cache,insert、update和delete操作默认会刷新这个cache。
//此处就不再看CacheExecutor的代码了,直接进入SimpleExecutor。SimpleExecutor的update方法继承的是父类BaseExecutor的。
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
}
SimpleExecutor中逻辑:
//先看一眼BaseExecutor中的update方法
public int update(MappedStatement ms, Object parameter) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
if (closed) throw new ExecutorException("Executor was closed.");
//清除一下本地缓存,主要逻辑在doUpdate方法中
clearLocalCache();
return doUpdate(ms, parameter);
}
//SimpleExecutor
public class SimpleExecutor extends BaseExecutor {
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
//先获取statementHandler
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
//再获取statement
stmt = prepareStatement(handler, ms.getStatementLog());
//然后执行
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}
}
//先来看一下Configuration.newStatementHandler
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//可以看到这边new的是一个RoutingStatementHandler,从名字上就可以看出这家伙不是真正做事情的,是做分发的。
//所以在RoutingStatementHandler的构造方法中,根据MappedStatement的类型(默认为Prepared类型),构造真正做事情的StatementHandler。
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
//statementHandler在此处的待遇和之前的executor一样,都是被interceptor代理。
//PS:所以如果想用拦截器做什么事情,可以拦截executor或者statementHandler的方法。
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
//PreparedStatementHandler的构造方法直接调用了父类BaseStatementHandler的构造方法:
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
this.configuration = mappedStatement.getConfiguration();
this.executor = executor;
this.mappedStatement = mappedStatement;
this.rowBounds = rowBounds;
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.objectFactory = configuration.getObjectFactory();
if (boundSql == null) { // issue #435, get the key before calculating the statement
//insert操作传过来的boundSql为null,肯定会走到这里。
//先生成key
generateKeys(parameterObject);
//获取boundSql
boundSql = mappedStatement.getBoundSql(parameterObject);
}
this.boundSql = boundSql;
//简单的封装,赋值
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
//生成key的逻辑
protected void generateKeys(Object parameter) {
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
ErrorContext.instance().store();
keyGenerator.processBefore(executor, mappedStatement, null, parameter);
ErrorContext.instance().recall();
}
//看一下SelectKeyGenerator是怎么做的
public class SelectKeyGenerator implements KeyGenerator {
public static final String SELECT_KEY_SUFFIX = "!selectKey";
private boolean executeBefore;
private MappedStatement keyStatement;
public SelectKeyGenerator(MappedStatement keyStatement, boolean executeBefore) {
this.executeBefore = executeBefore;
this.keyStatement = keyStatement;
}
public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
//如果是在执行前生成key
if (executeBefore) {
processGeneratedKeys(executor, ms, parameter);
}
}
public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
if (!executeBefore) {
processGeneratedKeys(executor, ms, parameter);
}
}
private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {
try {
final Configuration configuration = ms.getConfiguration();
if (parameter != null) {
String keyStatementName = ms.getId() + SELECT_KEY_SUFFIX;
if (configuration.hasStatement(keyStatementName)) {
if (keyStatement != null && keyStatement.getKeyProperties() != null) {
String keyProperty = keyStatement.getKeyProperties()[0]; //just one key property is supported
//MetaObject是一个工具类,可以获取封装的对象的属性的值或者设置属性的值
//获取设置的key对应的属性,以及查看parameter是否能够为该属性设置值
final MetaObject metaParam = configuration.newMetaObject(parameter);
if (keyProperty != null && metaParam.hasSetter(keyProperty)) {
// Do not close keyExecutor.
// The transaction will be closed by parent executor.
//此处执行一次查询操作,查询操作执行过程在其他文章中再说,这里先简单理解为执行一次查询操作获取到key就好了。
Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);
List<Object> values = keyExecutor.query(keyStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
if (values.size() > 1) {
throw new ExecutorException("Select statement for SelectKeyGenerator returned more than one value.");
}
metaParam.setValue(keyProperty, values.get(0));
}
}
}
}
} catch (Exception e) {
throw new ExecutorException("Error selecting key or setting result to parameter object. Cause: " + e, e);
}
}
}
//再看是如何获取BoundSql的
public final class MappedStatement {
public BoundSql getBoundSql(Object parameterObject) {
//此处的sqlSource是DynamicSqlSource
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
//如果parameterMappings为空或者size <= 0,发生这种状况的话,个人理解是,sql语句中没有变量或者所有的变量都是${}这样表示的
if (parameterMappings == null || parameterMappings.size() <= 0) {
//此时boundSql的parameterMappings取值为parameterMap.getParameterMappings。
boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
}
// check for nested result maps in parameter mappings (issue #30)
for (ParameterMapping pm : boundSql.getParameterMappings()) {
String rmId = pm.getResultMapId();
if (rmId != null) {
ResultMap rm = configuration.getResultMap(rmId);
if (rm != null) {
hasNestedResultMaps |= rm.hasNestedResultMaps();
}
}
}
return boundSql;
}
}
//SqlSource获取BoundSql的逻辑
public class DynamicSqlSource implements SqlSource {
public BoundSql getBoundSql(Object parameterObject) {
//此处相当于对parameterObject做了一层封装。
DynamicContext context = new DynamicContext(configuration, parameterObject);
//sqlNode应用context,这里也处理了动态sql语句中<if>, <foreach>这些情况。
//处理一些表达式的时候用到了OGNL
//另外,${}这样表示的变量,在这里被变量的具体value替换了。
rootSqlNode.apply(context);
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
//根据sql语句生成SqlSource对象
SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
//获取boundSql,sqlSource.getBoundSql方法中new了一个BoundSql,其构造方法也只是做了简单的赋值。
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
//这个地方相当于是说把parameterObject对象里,参数和值的对应关系保存在additionalParameter中。
for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
}
return boundSql;
}
}
public class SqlSourceBuilder extends BaseBuilder {
public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {
ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);
GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
//此处得到完成的sql语句,#{}这样表示的变量,会被"?"替换,具体对应的参数名字被放在handler.parameterMappings中
String sql = parser.parse(originalSql);
return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
}
}
至此,获取statementHandler的逻辑结束。
再看一眼SimpleExecutor.doUpdate做的事情
public class SimpleExecutor extends BaseExecutor {
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
//接下来看看这一部分逻辑,获取Statement。
stmt = prepareStatement(handler, ms.getStatementLog());
//执行具体的update操作。
return handler.update(stmt);
} finally {
//关闭Statement
closeStatement(stmt);
}
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
//这部分代码是不是看起来就有点眼熟的赶脚!
//从transaction中获取connection,如果log是debug级别,会为connection生成一个能够打印比较多log的代理。
Connection connection = getConnection(statementLog);
//handler为RoutingStatementHandler,它作为PreparedStatementHandler的代理。
//初始化statement
stmt = handler.prepare(connection);
//设置参数
handler.parameterize(stmt);
return stmt;
}
}
//初始化statement的过程
public class PreparedStatementHandler extends BaseStatementHandler {
//prepare方法继承的是父类BaseStatementHandler的
public Statement prepare(Connection connection) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
//初始化prepareStatement
statement = instantiateStatement(connection);
//设置语句超时时间,如果该条语句设置的超时时间为空,则从configuration获取。
setStatementTimeout(statement);
//设置语句每次返回结果条数,如果为空则忽略。
setFetchSize(statement);
return statement;
} catch (SQLException e) {
closeStatement(statement);
throw e;
} catch (Exception e) {
closeStatement(statement);
throw new ExecutorException("Error preparing statement. Cause: " + e, e);
}
}
protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = boundSql.getSql();
if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
String[] keyColumnNames = mappedStatement.getKeyColumns();
if (keyColumnNames == null) {
return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
} else {
return connection.prepareStatement(sql, keyColumnNames);
}
} else if (mappedStatement.getResultSetType() != null) {
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
} else {
return connection.prepareStatement(sql);
}
}
public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}
}
//DefaultParameterHandler.setParameters
public void setParameters(PreparedStatement ps) throws SQLException {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
//parameterMappings中保存着动态sql中每个参数的名字,additionalParameter中保存着参数对应的值。
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
MetaObject metaObject = parameterObject == null ? null : configuration.newMetaObject(parameterObject);
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
value = metaObject == null ? null : metaObject.getValue(propertyName);
}
TypeHandler typeHandler = parameterMapping.getTypeHandler();
if (typeHandler == null) {
throw new ExecutorException("There was no TypeHandler found for parameter " + propertyName + " of statement " + mappedStatement.getId());
}
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) jdbcType = configuration.getJdbcTypeForNull();
//真正为PrepareStatement设置参数的地方。
typeHandler.setParameter(ps, i + 1, value, jdbcType);
}
}
}
}
上面是获取statement的过程,下面就要具体执行update操作了,在PrepareStatementHandler中:
public class PreparedStatementHandler extends BaseStatementHandler {
public int update(Statement statement) throws SQLException {
//这几句都很熟
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
int rows = ps.getUpdateCount();
//这里同样是获取key的逻辑
Object parameterObject = boundSql.getParameterObject();
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
//如果keySelect语句设置的是在sql执行之后在执行,那么此处去或得下一个key。(具体逻辑和之前的一样)
keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
//返回影响的条数。
return rows;
}
}
至此,插入操作执行结束。