这里是parameterType接受的各种参数类型处理,在DefaultSqlSession中,此时走的是openSession后面的流程
/**
* ~~把参数包装成Collection~~
*
* @param object
* @return
*/
private Object wrapCollection(final Object object) {
if (object instanceof Collection) {
//参数若是Collection型,做collection标记
StrictMap<Object> map = new StrictMap<>();
map.put("collection", object);
if (object instanceof List) {
//参数若是List型,做list标记
map.put("list", object);
}
return map;
} else if (object != null && object.getClass().isArray()) {
//参数若是数组型,,做array标记
StrictMap<Object> map = new StrictMap<>();
map.put("array", object);
return map;
}
//参数若不是集合型,直接返回原来值
return object;
}
下面是整个代码
/**
* Copyright ${license.git.copyrightYears} the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.session.defaults;
import org.apache.ibatis.binding.BindingException;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.exceptions.ExceptionFactory;
import org.apache.ibatis.exceptions.TooManyResultsException;
import org.apache.ibatis.executor.BatchResult;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.result.DefaultMapResultHandler;
import org.apache.ibatis.executor.result.DefaultResultContext;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;
/**
* 默认SqlSession实现
* 非线程安全
* The default implementation for {@link SqlSession}.
* Note that this class is not Thread-Safe.
*
* @author Clinton Begin
*/
public class DefaultSqlSession implements SqlSession {
private final Configuration configuration;
private final Executor executor;
/**
* 是否自动提交
*/
private final boolean autoCommit;
private boolean dirty;
private List<Cursor<?>> cursorList;
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}
public DefaultSqlSession(Configuration configuration, Executor executor) {
this(configuration, executor, false);
}
@Override
public <T> T selectOne(String statement) {
return this.selectOne(statement, null);
}
/**
* 核心selectOne
*
* @param statement
* @param
* @return
*/
@Override
public <T> T selectOne(String statement, Object parameter) {
// Popular vote was to return null on 0 results and throw exception on too many.
//转而去调用selectList,很简单的,如果得到0条则返回null,得到1条则返回1条,得到多条报TooManyResultsException错
//特别需要注意的是当没有查询到结果的时候就会返回null。因此一般建议在mapper中编写resultType的时候使用包装类型
//而不是基本类型,比如推荐使用Integer而不是int。这样就可以避免NPE(NullPointerException)
List<T> list = this.selectList(statement, parameter);
if (list.size() == 1) {
return list.get(0);
} 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;
}
}
@Override
public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
return this.selectMap(statement, null, mapKey, RowBounds.DEFAULT);
}
@Override
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
return this.selectMap(statement, parameter, mapKey, RowBounds.DEFAULT);
}
/**
* //核心selectMap
*
* @param statement Unique identifier matching the statement to use.
* @param parameter A parameter object to pass to the statement.
* @param mapKey The property to use as key for each value in the list.
* @param rowBounds Bounds to limit object retrieval
* @param
* @param
* @return
*/
@Override
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
//调用selectList
final List<? extends V> list = selectList(statement, parameter, rowBounds);
final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<>(mapKey,
configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory());
final DefaultResultContext<V> context = new DefaultResultContext<>();
for (V o : list) {
//循环用DefaultMapResultHandler处理每条记录
context.nextResultObject(o);
mapResultHandler.handleResult(context);
}
//注意这个DefaultMapResultHandler里面存了所有已处理的记录(内部实现可能就是一个Map),最后再返回一个Map
return mapResultHandler.getMappedResults();
}
@Override
public <T> Cursor<T> selectCursor(String statement) {
return selectCursor(statement, null);
}
@Override
public <T> Cursor<T> selectCursor(String statement, Object parameter) {
return selectCursor(statement, parameter, RowBounds.DEFAULT);
}
@Override
public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
Cursor<T> cursor = executor.queryCursor(ms, wrapCollection(parameter), rowBounds);
registerCursor(cursor);
return cursor;
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
@Override
public <E> List<E> selectList(String statement) {
return this.selectList(statement, null);
}
@Override
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
/**
* 核心selectList
*
* @param statement Unique identifier matching the statement to use.
* @param parameter A parameter object to pass to the statement.
* @param rowBounds Bounds to limit object retrieval
* @param
* @return
*/
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
//根据statement id找到对应的MappedStatement
MappedStatement ms = configuration.getMappedStatement(statement);
//转而用执行器来查询结果,注意这里传入的ResultHandler是null
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
@Override
public void select(String statement, Object parameter, ResultHandler handler) {
select(statement, parameter, RowBounds.DEFAULT, handler);
}
@Override
public void select(String statement, ResultHandler handler) {
select(statement, null, RowBounds.DEFAULT, handler);
}
/**
* 核心select,带有ResultHandler,和selectList代码差不多的,区别就一个ResultHandler
*
* @param statement Unique identifier matching the statement to use.
* @param parameter
* @param rowBounds RowBound instance to limit the query results
* @param handler ResultHandler that will handle each retrieved row
*/
@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();
}
}
@Override
public int insert(String statement) {
return insert(statement, null);
}
@Override
public int insert(String statement, Object parameter) {
//insert也是调用update
return update(statement, parameter);
}
@Override
public int update(String statement) {
return update(statement, null);
}
/**
* 核心update
*
* @param statement Unique identifier matching the statement to execute.
* @param parameter A parameter object to pass to the statement.
* @return
*/
@Override
public int update(String statement, Object parameter) {
try {
//每次要更新之前,dirty标志设为true
dirty = true;
MappedStatement ms = configuration.getMappedStatement(statement);
//转而用执行器来update结果
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
@Override
public int delete(String statement) {
//delete也是调用update
return update(statement, null);
}
@Override
public int delete(String statement, Object parameter) {
return update(statement, parameter);
}
@Override
public void commit() {
commit(false);
}
/**
* 核心commit
*
* @param force forces connection commit
*/
@Override
public void commit(boolean force) {
try {
//转而用执行器来commit
executor.commit(isCommitOrRollbackRequired(force));
//每次commit之后,dirty标志设为false
dirty = false;
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error committing transaction. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
@Override
public void rollback() {
rollback(false);
}
/**
* 核心rollback
*
* @param force forces connection rollback
*/
@Override
public void rollback(boolean force) {
try {
//转而用执行器来rollback
executor.rollback(isCommitOrRollbackRequired(force));
//每次rollback之后,dirty标志设为false
dirty = false;
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error rolling back transaction. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
/**
* 核心flushStatements
*
* @return
*/
@Override
public List<BatchResult> flushStatements() {
try {
//转而用执行器来flushStatements
return executor.flushStatements();
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error flushing statements. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
/**
* 核心close
*/
@Override
public void close() {
try {
//转而用执行器来close
executor.close(isCommitOrRollbackRequired(false));
closeCursors();
//每次close之后,dirty标志设为false
dirty = false;
} finally {
ErrorContext.instance().reset();
}
}
private void closeCursors() {
if (cursorList != null && cursorList.size() != 0) {
for (Cursor<?> cursor : cursorList) {
try {
cursor.close();
} catch (IOException e) {
throw ExceptionFactory.wrapException("Error closing cursor. Cause: " + e, e);
}
}
cursorList.clear();
}
}
@Override
public Configuration getConfiguration() {
return configuration;
}
@Override
public <T> T getMapper(Class<T> type) {
//最后会去调用MapperRegistry.getMapper
return configuration.getMapper(type, this);
}
@Override
public Connection getConnection() {
try {
return executor.getTransaction().getConnection();
} catch (SQLException e) {
throw ExceptionFactory.wrapException("Error getting a new connection. Cause: " + e, e);
}
}
/**
* 清理缓存
*/
@Override
public void clearCache() {
executor.clearLocalCache();
}
private <T> void registerCursor(Cursor<T> cursor) {
if (cursorList == null) {
cursorList = new ArrayList<>();
}
cursorList.add(cursor);
}
/**
* 检查是否需要强制commit或rollback
*
* @param force
* @return
*/
private boolean isCommitOrRollbackRequired(boolean force) {
return (!autoCommit && dirty) || force;
}
/**
* 把参数包装成Collection
*
* @param object
* @return
*/
private Object wrapCollection(final Object object) {
if (object instanceof Collection) {
//参数若是Collection型,做collection标记
StrictMap<Object> map = new StrictMap<>();
map.put("collection", object);
if (object instanceof List) {
//参数若是List型,做list标记
map.put("list", object);
}
return map;
} else if (object != null && object.getClass().isArray()) {
//参数若是数组型,,做array标记
StrictMap<Object> map = new StrictMap<>();
map.put("array", object);
return map;
}
//参数若不是集合型,直接返回原来值
return object;
}
/**
* 严格的Map,如果找不到对应的key,直接抛BindingException例外,而不是返回null
*
* @param
*/
public static class StrictMap<V> extends HashMap<String, V> {
private static final long serialVersionUID = -5741767162221585340L;
@Override
public V get(Object key) {
if (!super.containsKey(key)) {
throw new BindingException("Parameter '" + key + "' not found. Available parameters are " + this.keySet());
}
return super.get(key);
}
}
}
看一下,StrictMap
/**
* 严格的Map,如果找不到对应的key,直接抛BindingException例外,而不是返回null
*
* @param
*/
public static class StrictMap<V> extends HashMap<String, V> {
private static final long serialVersionUID = -5741767162221585340L;
@Override
public V get(Object key) {
if (!super.containsKey(key)) {
throw new BindingException("Parameter '" + key + "' not found. Available parameters are " + this.keySet());
}
return super.get(key);
}
}