接第二篇中MapperProxy方法的invoke方法讲起
MapperProxy
这个类是每一个Mapper的动态代理对象对应的InvocationHandler,当调用代理对象的方法时,都会调用到该方法的invoke方法,并传入代理对象,方法,参数。
首先判断当前方法是不是继承自Object的方法,如果是,直接执行原方法。否则生成一个MapperMethod对象,用来执行代理方法。而这个类就是执行增删改查的关键类。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
MapperMethod
// SQL
private final SqlCommand command;
// 方法签名
private final MethodSignature method;
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new SqlCommand(config, mapperInterface, method);
this.method = new MethodSignature(config, method);
}
SqlCommand
- 查找Statement
public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
String statementName = mapperInterface.getName() + "." + method.getName();
MappedStatement ms = null;
// 根据之前解析过的XML或者接口是否已经有该statement了
if (configuration.hasStatement(statementName)) {
ms = configuration.getMappedStatement(statementName);
// 如果是继承的接口上的方法,判断以父接口名 + 方法名是否存在statement
} else if (!mapperInterface.equals(method.getDeclaringClass())) { // issue #35
String parentStatementName = method.getDeclaringClass().getName() + "." + method.getName();
if (configuration.hasStatement(parentStatementName)) {
ms = configuration.getMappedStatement(parentStatementName);
}
}
// 如果没找到,判断是否是flush,如果有表示该方法仅用于刷新缓存
if (ms == null) {
if(method.getAnnotation(Flush.class) != null){
name = null;
type = SqlCommandType.FLUSH;
} else {
throw new BindingException("Invalid bound statement (not found): " + statementName);
}
} else {
name = ms.getId();
type = ms.getSqlCommandType();
if (type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + name);
}
}
}
MethodSignature
- 分析方法,解析出方法签名对象
public MethodSignature(Configuration configuration, Method method) {
// 返回类型
this.returnType = method.getReturnType();
// 是否返回void
this.returnsVoid = void.class.equals(this.returnType);
// 是否返回多个
this.returnsMany = (configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray());
// 获取@MapKey的值
this.mapKey = getMapKey(method);
// 是否返回Map
this.returnsMap = (this.mapKey != null);
// 是否有标注有@Params的参数
this.hasNamedParameters = hasNamedParams(method);
// 参数中RowBounds的索引
this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
// 参数中ResultHandler的索引
this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
// 获取参数名称列表,用于后续替换SQL中的参数,逻辑为如果标注了@Params,就使用@Params的值,如果没有就使用参数所在下标
this.params = Collections.unmodifiableSortedMap(getParams(method, this.hasNamedParameters));
}
执行execute方法
- 根据不同的statement获得的不通SqlCommandType,执行不同的逻辑
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
if (SqlCommandType.INSERT == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
} else if (SqlCommandType.UPDATE == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
} else if (SqlCommandType.DELETE == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
} else if (SqlCommandType.SELECT == command.getType()) {
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
}
} else if (SqlCommandType.FLUSH == command.getType()) {
result = sqlSession.flushStatements();
} else {
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}
- 先来分析SELECT方法,分为几种情况
- 无返回值且参数中有ResultHandler,执行executeWithResultHandler(sqlSession, args);
private void executeWithResultHandler(SqlSession sqlSession, Object[] args) {
MappedStatement ms = sqlSession.getConfiguration().getMappedStatement(command.getName());
if (void.class.equals(ms.getResultMaps().get(0).getType())) {
throw new BindingException("method " + command.getName()
+ " needs either a @ResultMap annotation, a @ResultType annotation,"
+ " or a resultType attribute in XML so a ResultHandler can be used as a parameter.");
}
Object param = method.convertArgsToSqlCommandParam(args);
if (method.hasRowBounds()) {
RowBounds rowBounds = method.extractRowBounds(args);
sqlSession.select(command.getName(), param, rowBounds, method.extractResultHandler(args));
} else {
sqlSession.select(command.getName(), param, method.extractResultHandler(args));
}
}
- 转换参数值,将传入的参数进行转换
- 如果没有参数,返回null
- 如果有一个参数并且没有@Params注解的参数,返回第一个参数值
- 如果有多个参数,新建ParamMap对象,首先按之前方法签名中解析到的paramName作为key,参数值对应参数下标获取参数值作为value,同时再新增param1,param2按顺序作为key,再存入一份。即未来可以通过“0,1,2”或者“param1,param2, param3”或者“actualParamName1,actualParamName2,actualParamName3”来获取到参数值替换Sql中的参数名称
public Object convertArgsToSqlCommandParam(Object[] args) {
final int paramCount = params.size();
if (args == null || paramCount == 0) {
return null;
} else if (!hasNamedParameters && paramCount == 1) {
return args[params.keySet().iterator().next().intValue()];
} else {
final Map<String, Object> param = new ParamMap<Object>();
int i = 0;
for (Map.Entry<Integer, String> entry : params.entrySet()) {
param.put(entry.getValue(), args[entry.getKey().intValue()]);
// issue #71, add param names as param1, param2...but ensure backward compatibility
final String genericParamName = "param" + String.valueOf(i + 1);
if (!param.containsKey(genericParamName)) {
param.put(genericParamName, args[entry.getKey()]);
}
i++;
}
return param;
}
}
- 执行SqlSession的select方法,分为有RowBounds和无RowBounds参数两种,这里的sqlSession目前的实现是SqlSessionTemplate,是在自动注入MapperFactoryBean的时候注入的,实际就是调用了sqlSessionTemplate的select方法
if (method.hasRowBounds()) {
RowBounds rowBounds = method.extractRowBounds(args);
sqlSession.select(command.getName(), param, rowBounds, method.extractResultHandler(args));
} else {
sqlSession.select(command.getName(), param, method.extractResultHandler(args));
}
- SqlSesstionTemplate是调用了他的一个属性sqlSessionProxy动态代理对象的select方法,这个对象在实例化SqlSessionTemplate时创建,是一个JDK动态代理对象,该代理对象传入的InvocationHandler是SqlSessionInterceptor,
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
this.sqlSessionProxy.select(statement, parameter, rowBounds, handler);
}
- SqlSessionInterceptor这个类的invoke方法拦截select方法,在这个方法中就会去获取session,并执行目标方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 获取session,通过Spring提供的TransactionSynchronizationManager获取当前线程是否绑定过一个SqlSessionHolder,如果绑定过,则可以直接重用原Session,如果没有,重新打开一个新的session
// 这里最终会获取到一个DefaultSqlSession
SqlSession sqlSession = getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator);
try {
// 执行目标方法,跳转到DefaultSqlSession的方法中
Object result = method.invoke(sqlSession, args);
// 如果不是Spring管理的session,则强制提交
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
// force commit even on non-dirty sessions because some databases require
// a commit/rollback before calling close()
sqlSession.commit(true);
}
return result;
} catch (Throwable t) {
Throwable unwrapped = unwrapThrowable(t);
if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
// release the connection to avoid a deadlock if the translator is no loaded. See issue #22
// 关闭session,释放资源
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
sqlSession = null;
Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw unwrapped;
} finally {
// 关闭session,释放资源
if (sqlSession != null) {
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
}
- 获取DefaultSqlSession
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
// 获取到之前创建的事务工厂,默认为SpringManagedTransactionFactory
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
// 创建事务,默认为SpringManagedTransaction
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
// 创建执行器,默认为SIMPLE
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();
}
}
// 该方法在Configuration中
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
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);
}
// 如果开启了缓存,其实默认是开启的,装饰器模式装饰一个CachingExecutor
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
// 为执行器增强插件功能
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
- DefaultSqlSession.select方法
@Override
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
executor.query(ms, wrapCollection(parameter), rowBounds, handler);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
- 默认调用CachingExecutor的query方法
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameterObject);
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
- 利用MappedStatement获取BoundSql,
public BoundSql getBoundSql(Object parameterObject) {
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings == null || parameterMappings.isEmpty()) {
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;
}
- 继续调用DynamicSqlSource的getBoundSql方法
public BoundSql getBoundSql(Object parameterObject) {
DynamicContext context = new DynamicContext(configuration, parameterObject);
// 这里会将SQL中的${}替换为实际传入的参数的值
rootSqlNode.apply(context);
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
/**
parse方法[代码如下]中替换了#{param1}的参数为?,并记录下了ParameterMapping
ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);
GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
String sql = parser.parse(originalSql);
return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
*/
SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
// 前面所有的都是在根据参数于条件判断等获取到真正的Sql,即由DynamicSqlSource转换成StaticSqlSource,去除了像<choose>,<if>这之类的条件判断,替换了#{param1}这样的参数
// 接下来就是调用StaticSqlSource进行参数替换
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
}
return boundSql;
}
- 利用MappesStatement,parameter,rowBounds,以及上面获取到的BoundSql创建缓存的Key
- 调用CachingExecutor的query查询数据,这个类是SimpleExecutor的装饰器,先查询是否有缓存,如果有,直接返回
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) {
// 判断是否需要刷新缓存,这个方法中会给原来的Cache再装饰一层TransactionCache,调用clear方法,会将其一个clearOnCommit标识改为true,一旦被标识为true之后,后续再从缓存中获取时,直接返回null,
// 如果有事务提交,也会直接将所有缓存先清空,再flush
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, parameterObject, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
// 有Cache,但Cache中没有缓存数据,直接调用SimpleExecutor去查询
if (list == null) {
list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
// 没有设置缓存直接查
return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
- BaseExecutor,SimpleExecutor继承自BaseExecutor,query由BaseExecutor实现
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 (closed) {
throw new ExecutorException("Executor was closed.");
}
// 需要刷新缓存的化,清除BaseExecutor中的PerpetualCache中的缓存,注意,这里的PerpetualCache和之前解析<cache>时创建的不同,这里的是一定会生成的本地缓存,
// 而之前那个是二级缓存,只有在cacheEnabled配置为true并且Mapper.xml中配置了<cache>才会生效
// 这里的本地缓存生命周期很短,因为这个Executor实际上是创建DefaultSqlSession是新建的一个属性,因此属于session独享的,一旦session关闭后,其他session是获取不到该session下的本地缓存的
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
// 本地缓存有
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
// 本地缓存未查询到数据则从数据库去查
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
// 设置了本地缓存作用域为STATEMENT的话,每次都清除本地缓存
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
- 从数据库查会通过Configuration新建一个重要的组件叫StatementHandler,默认实现为PreparedStatementHandler,可通过在Mapper xml中设置statementType属性修改,这里插件又排上用场了,可以为StatementHandler装饰插件,不仅是在这里,在新建RoutingStatementHandler这个类时,会根据statementType选择不同的statementHandler,比如在new默认的PreparedStatementHandler时,会调用父类BaseStatementHandler的构造方法,在这个方法中还会调用configuration.newParameterHandler,configuration.newResultSetHandler,这两个方法同样会为ParameterHandler,和ResultSetHandler添加插件功能。因此至此,我们直到了为Mabatis可以在4个地方为其增加插件功能。总结如下:
- Executor:执行器,可通过增强他改变查询,本地缓存,提交/回滚等功能的变更
- StatementHandler:可改变sql的生成,比如在这类拦截prepare,然后修改sql,实现分页
- ResultSetHandler:可以改变返回结果的生成方式
- ParameterHandler: 参数处理器,可改变参数赋值的行为
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) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
ResultHandler resultHandler, BoundSql boundSql) {
ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
return resultSetHandler;
}
- 然后开始构造PreparedStatement
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
// 获取数据库连接
Connection connection = getConnection(statementLog);
// 生成PreparedStatement,这里直接把代码copy过来
/**
public Statement prepare(Connection connection) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
// 实例化statement
statement = instantiateStatement(connection);
// 设置超时时间
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);
}
}
*/
stmt = handler.prepare(connection);
// 为PreparedStatement中的? 复制,主要逻辑是根据ParameterMapping获取到参数的下标,值以及类型处理器,通过不同的类型处理器对?赋值
handler.parameterize(stmt);
return stmt;
}
- 调用ResultSetHandler的handleResultSets方法处理返回结果
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
final List<Object> multipleResults = new ArrayList<Object>();
int resultSetCount = 0;
// ResultSet的包装类
ResultSetWrapper rsw = getFirstResultSet(stmt);
// 获取之前定义的ResultMap
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
// 验证是否获取到了结果,但resultMap却未指定
validateResultMapsCount(rsw, resultMapCount);
//
while (rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = resultMaps.get(resultSetCount);
handleResultSet(rsw, resultMap, multipleResults, null);
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
String[] resultSets = mappedStatement.getResulSets();
if (resultSets != null) {
while (rsw != null && resultSetCount < resultSets.length) {
ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
if (parentMapping != null) {
String nestedResultMapId = parentMapping.getNestedResultMapId();
ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
handleResultSet(rsw, resultMap, null, parentMapping);
}
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
}
return collapseSingleResultList(multipleResults);
}
- handleResultSet方法,获取ResultSet中的值,根据之前配置的映射或者对象属性,新建并逐层返回
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
throws SQLException {
DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
// RowBounds逻辑分页,跳过不要的行
skipRows(rsw.getResultSet(), rowBounds);
while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
// 鉴别器,很少用
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
// 创建对象,并根据ResultMap映射为属性赋值,首先赋值未显式指定<property>的属性,然后指定了<property>的属性
Object rowValue = getRowValue(rsw, discriminatedResultMap);
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
- 至此executeWithResultHandler主流程基本就结束了,以下三种查询的流程基本一致,只是将查询到的list做了不同的封装处理,如executeMany将list进行指定对象的封装,executeForMap采用DefaultMapResultHandler将对象转换成map
- 返回集合,执行executeForMany(sqlSession, args);
- 返回Map,执行executeForMap(sqlSession, args);
- 其他,直接转换参数,调用sqlSession.selectOne()方法
- 分析了Select方法,再来看一个INSERT方法
- 同样的首先先转换可用参数名,如param1,param2等等
if (SqlCommandType.INSERT == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
}
- 直接调用insert方法,insert方法在DefaultSqlSession中又调用了update方法
public int update(String statement, Object parameter) {
try {
dirty = true;
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
- 将集合类对象转换成MapperXml中能识别的collection,list,或者array
private Object wrapCollection(final Object object) {
if (object instanceof Collection) {
StrictMap<Object> map = new StrictMap<Object>();
map.put("collection", object);
if (object instanceof List) {
map.put("list", object);
}
return map;
} else if (object != null && object.getClass().isArray()) {
StrictMap<Object> map = new StrictMap<Object>();
map.put("array", object);
return map;
}
return object;
}
- 调用CachingExecutor,同样的,和query操作一样,如果开启了二级缓存,首先判断是否需要刷新缓存,然后调用BaseExecutor的update方法
public int update(MappedStatement ms, Object parameterObject) throws SQLException {
flushCacheIfRequired(ms);
return delegate.update(ms, parameterObject);
}
- 事务类操作首先都刷新本地缓存, 然后调用SimpleExecutor的doUpdate方法
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.");
}
clearLocalCache();
return doUpdate(ms, parameter);
}
- 和query一样,默认新建PreparedStatementHandler处理器,然后替换其中的?赋值,新建PreparedStatement, 最后执行PrepareStatementHandler的update方法并返回,注意,这里在new PreparedStatementHandler同样会触发父类BaseStatementHandler的构造方法,这里会执行generateKeys(parameterObject)方法,目的是在执行真正的插入语句之前,先执行SelectKeyGenerator的方法,生成主键。
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);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}
- 执行insert语句,并返回操作成功的数量,如果指定了需要使用useGeneratedKeys,或这个在Mapper XML中使用了<selectKey>标签,这个会在最开始解析XML时创建,见上一篇文章,那么此处需要执行查询语句,分别会调用Jdbc3KeyGenerator和SelectKeyGenerator的processAfter方法为传入的参数的主键属性赋值。
public int update(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
int rows = ps.getUpdateCount();
Object parameterObject = boundSql.getParameterObject();
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
return rows;
}
- insert的流程比较简单,大致就分析到这里吧。