BoundSql 一次可执行的SQL封装
public class BoundSql {
//SQL语句
private final String sql;
//ParameterMapping 数组
private final List<ParameterMapping> parameterMappings;
//参数对象
private final Object parameterObject;
//附加的参数集合
private final Map<String, Object> additionalParameters;
//MetaObject对象
private final MetaObject metaParameters;
public BoundSql(Configuration configuration, String sql, List<ParameterMapping> parameterMappings, Object parameterObject) {
this.sql = sql;
this.parameterMappings = parameterMappings;
this.parameterObject = parameterObject;
this.additionalParameters = new HashMap<>();
this.metaParameters = configuration.newMetaObject(additionalParameters);
}
public String getSql() {
return sql;
}
public List<ParameterMapping> getParameterMappings() {
return parameterMappings;
}
public Object getParameterObject() {
return parameterObject;
}
public boolean hasAdditionalParameter(String name) {
String paramName = new PropertyTokenizer(name).getName();
return additionalParameters.containsKey(paramName);
}
public void setAdditionalParameter(String name, Object value) {
metaParameters.setValue(name, value);
}
public Object getAdditionalParameter(String name) {
return metaParameters.getValue(name);
}
}
ParameterMapping参数映射
public class ParameterMapping {
private Configuration configuration;
//属性的名称
private String property;
//参数类型
private ParameterMode mode;
//java类型
private Class<?> javaType = Object.class;
//jdbc类型
private JdbcType jdbcType;
//对于数值类型,还有一个小数保留位数的设置,确定小数点后保留的位数
private Integer numericScale;
//typeHandler对象
private TypeHandler<?> typeHandler;
//存储过程中使用
private String resultMapId;
//存储过程中使用
private String jdbcTypeName;
private String expression;
private ParameterMapping() {
}
public static class Builder {
private ParameterMapping parameterMapping = new ParameterMapping();
public Builder(Configuration configuration, String property, TypeHandler<?> typeHandler) {
parameterMapping.configuration = configuration;
parameterMapping.property = property;
parameterMapping.typeHandler = typeHandler;
parameterMapping.mode = ParameterMode.IN;
}
public Builder(Configuration configuration, String property, Class<?> javaType) {
parameterMapping.configuration = configuration;
parameterMapping.property = property;
parameterMapping.javaType = javaType;
parameterMapping.mode = ParameterMode.IN;
}
public Builder mode(ParameterMode mode) {
parameterMapping.mode = mode;
return this;
}
public Builder javaType(Class<?> javaType) {
parameterMapping.javaType = javaType;
return this;
}
public Builder jdbcType(JdbcType jdbcType) {
parameterMapping.jdbcType = jdbcType;
return this;
}
public Builder numericScale(Integer numericScale) {
parameterMapping.numericScale = numericScale;
return this;
}
public Builder resultMapId(String resultMapId) {
parameterMapping.resultMapId = resultMapId;
return this;
}
public Builder typeHandler(TypeHandler<?> typeHandler) {
parameterMapping.typeHandler = typeHandler;
return this;
}
public Builder jdbcTypeName(String jdbcTypeName) {
parameterMapping.jdbcTypeName = jdbcTypeName;
return this;
}
public Builder expression(String expression) {
parameterMapping.expression = expression;
return this;
}
public ParameterMapping build() {
resolveTypeHandler();
validate();
return parameterMapping;
}
private void validate() {
if (ResultSet.class.equals(parameterMapping.javaType)) {
if (parameterMapping.resultMapId == null) {
throw new IllegalStateException("Missing resultmap in property '"
+ parameterMapping.property + "'. "
+ "Parameters of type java.sql.ResultSet require a resultmap.");
}
} else {
if (parameterMapping.typeHandler == null) {
throw new IllegalStateException("Type handler was null on parameter mapping for property '"
+ parameterMapping.property + "'. It was either not specified and/or could not be found for the javaType ("
+ parameterMapping.javaType.getName() + ") : jdbcType (" + parameterMapping.jdbcType + ") combination.");
}
}
}
private void resolveTypeHandler() {
if (parameterMapping.typeHandler == null && parameterMapping.javaType != null) {
Configuration configuration = parameterMapping.configuration;
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
parameterMapping.typeHandler = typeHandlerRegistry.getTypeHandler(parameterMapping.javaType, parameterMapping.jdbcType);
}
}
}
public String getProperty() {
return property;
}
/**
* Used for handling output of callable statements
* @return
*/
public ParameterMode getMode() {
return mode;
}
/**
* Used for handling output of callable statements
* @return
*/
public Class<?> getJavaType() {
return javaType;
}
/**
* Used in the UnknownTypeHandler in case there is no handler for the property type
* @return
*/
public JdbcType getJdbcType() {
return jdbcType;
}
/**
* Used for handling output of callable statements
* @return
*/
public Integer getNumericScale() {
return numericScale;
}
/**
* Used when setting parameters to the PreparedStatement
* @return
*/
public TypeHandler<?> getTypeHandler() {
return typeHandler;
}
/**
* Used for handling output of callable statements
* @return
*/
public String getResultMapId() {
return resultMapId;
}
/**
* Used for handling output of callable statements
* @return
*/
public String getJdbcTypeName() {
return jdbcTypeName;
}
/**
* Not used
* @return
*/
public String getExpression() {
return expression;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("ParameterMapping{");
//sb.append("configuration=").append(configuration); // configuration doesn't have a useful .toString()
sb.append("property='").append(property).append('\'');
sb.append(", mode=").append(mode);
sb.append(", javaType=").append(javaType);
sb.append(", jdbcType=").append(jdbcType);
sb.append(", numericScale=").append(numericScale);
//sb.append(", typeHandler=").append(typeHandler); // typeHandler also doesn't have a useful .toString()
sb.append(", resultMapId='").append(resultMapId).append('\'');
sb.append(", jdbcTypeName='").append(jdbcTypeName).append('\'');
sb.append(", expression='").append(expression).append('\'');
sb.append('}');
return sb.toString();
}
}
ParameterMode
public enum ParameterMode {
//out和inout都是存储过程中使用的
IN, OUT, INOUT
}
ParameterHandler
public interface ParameterHandler {
//参数对象
Object getParameterObject();
//设置PreparedStatement的占位符参数
void setParameters(PreparedStatement ps)
throws SQLException;
}
DefaultParameterHandler 默认的实现类
public class DefaultParameterHandler implements ParameterHandler {
//typeHandler注册中心
private final TypeHandlerRegistry typeHandlerRegistry;
//对应的sql节点的信息
private final MappedStatement mappedStatement;
//用户传入的参数
private final Object parameterObject;
//SQL语句信息,其中还包括占位符和参数名称信息
private final BoundSql boundSql;
private final Configuration configuration;
public DefaultParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
this.mappedStatement = mappedStatement;
this.configuration = mappedStatement.getConfiguration();
this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
this.parameterObject = parameterObject;
this.boundSql = boundSql;
}
@Override
public Object getParameterObject() {
return parameterObject;
}
@Override
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
//从boundSql中获取sql语句的占位符对应的参数信息
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
//遍历这个参数列表,把参数设置到PreparedStatement中
if (parameterMappings != null) {
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)) { // 获取对应的实参值
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
TypeHandler typeHandler = parameterMapping.getTypeHandler();//从parameterMapping中获取typeHandler对象
JdbcType jdbcType = parameterMapping.getJdbcType();//获取参数对应的jdbcType
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
//为statment中的占位符绑定参数
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
} catch (SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}
}
分析完了SQL语句的解析,接下来进入执行阶段。
执行
对应的是executor包,每个包对应一个功能:
statement包:对数据库发起SQL命令。
parameter包:实现设置PreparedStatement的占位符参数。
keygen包,实现数据库主键生成功能。
resultset包,将结果映射成对应的对象。
result包,被resultset包所调用,用作结果的处理。
loader包,实现延迟加载的功能。
根目录:其中是Executor接口及其实现类,作为SLQ执行的核心入口。
Executor
public interface Executor {
//空ResultHandler对象的枚举
ResultHandler NO_RESULT_HANDLER = null;
//执行增删改的三种类型sql语句
int update(MappedStatement ms, Object parameter) throws SQLException;
//查询,带 ResultHandler + CacheKey + BoundSql
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
//查询,带 ResultHandler
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
//执行select类型的sql语句,返回结果为游标
<E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;
//刷新批处理语句
List<BatchResult> flushStatements() throws SQLException;
//提交事务
void commit(boolean required) throws SQLException;
//回滚事务
void rollback(boolean required) throws SQLException;
//创建缓存key值
CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
//是否缓存
boolean isCached(MappedStatement ms, CacheKey key);
//清空一级缓存
void clearLocalCache();
//延迟加载一级缓存数据
void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
//获取事务对象
Transaction getTransaction();
//关闭executor对象
void close(boolean forceRollback);
//判断是否关闭
boolean isClosed();
void setExecutorWrapper(Executor executor);
}
Executor的BaseExecutor实现类是一级缓存,CachingExecutor是二级缓存。
BaseExecutor
public abstract class BaseExecutor implements Executor {
private static final Log log = LogFactory.getLog(BaseExecutor.class);
protected Transaction transaction;//事务对象
protected Executor wrapper;//封装的Executor对象
protected ConcurrentLinkedQueue<DeferredLoad> deferredLoads;//延迟加载的队列
//每个SqlSession都会创建出一个Executor对象,而每个Executor对象都有个缓存,默认开启,无法关闭
protected PerpetualCache localCache;//一级缓存的实现,PerpetualCache,本地缓存
protected PerpetualCache localOutputParameterCache;//本地输出类型的参数缓存
protected Configuration configuration;//全局唯一configuration对象的引用
protected int queryStack;//用于递归嵌套查询的的层数
//是否关闭
private boolean closed;
protected BaseExecutor(Configuration configuration, Transaction transaction) {
this.transaction = transaction;
this.deferredLoads = new ConcurrentLinkedQueue<>();
this.localCache = new PerpetualCache("LocalCache");
this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache");
this.closed = false;
this.configuration = configuration;
this.wrapper = this;
}
@Override
//获得事务对象
public Transaction getTransaction() {
if (closed) {
throw new ExecutorException("Executor was closed.");
}
return transaction;
}
@Override
//关闭执行器
public void close(boolean forceRollback) {
try {
try {
//回滚事务
rollback(forceRollback);
} finally {
//关闭事务
if (transaction != null) {
transaction.close();
}
}
} catch (SQLException e) {
// Ignore. There's nothing that can be done at this point.
log.warn("Unexpected exception on closing transaction. Cause: " + e);
} finally {
//将变量清空
transaction = null;
deferredLoads = null;
localCache = null;
localOutputParameterCache = null;
closed = true;
}
}
@Override
public boolean isClosed() {
return closed;
}
@Override
//执行写操作
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);
}
@Override
//刷入批处理语句
public List<BatchResult> flushStatements() throws SQLException {
return flushStatements(false);
}
public List<BatchResult> flushStatements(boolean isRollBack) throws SQLException {
if (closed) {
throw new ExecutorException("Executor was closed.");
}
//执行刷入批处理语句
return doFlushStatements(isRollBack);
}
//读操作
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//获取sql语句信息,包括占位符,参数等信息
BoundSql boundSql = ms.getBoundSql(parameter);
//拼装缓存的key值
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
@SuppressWarnings("unchecked")
@Override
//读操作
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) {//检查当前executor是否关闭
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {//非嵌套查询,并且FlushCache配置为true,则需要清空一级缓存
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();
}
deferredLoads.clear();
//对应的是LocalCacheScope对象,有会话级(session)以及SQL语句级(statement)。
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {//如果当前sql的一级缓存配置为STATEMENT,查询完既清空一集缓存
clearLocalCache();
}
}
return list;
}
//执行查询,返回的结果为Cursor游标对象
@Override
public <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException {
//获得BoundSql对象
BoundSql boundSql = ms.getBoundSql(parameter);
//执行查询
return doQueryCursor(ms, parameter, rowBounds, boundSql);
}
@Override
public void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType) {
if (closed) {
throw new ExecutorException("Executor was closed.");
}
DeferredLoad deferredLoad = new DeferredLoad(resultObject, property, key, localCache, configuration, targetType);
if (deferredLoad.canLoad()) {
deferredLoad.load();
} else {
deferredLoads.add(new DeferredLoad(resultObject, property, key, localCache, configuration, targetType));
}
}
//创建CacheKey对象
@Override
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
if (closed) {
throw new ExecutorException("Executor was closed.");
}
//创建CacheKey对象
CacheKey cacheKey = new CacheKey();
//设置 id、offset、limit、sql 到 CacheKey 对象中
cacheKey.update(ms.getId());
cacheKey.update(rowBounds.getOffset());
cacheKey.update(rowBounds.getLimit());
cacheKey.update(boundSql.getSql());
//设置 ParameterMapping 数组的元素对应的每个 value 到 CacheKey 对象中
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
// mimic DefaultParameterHandler logic
for (ParameterMapping parameterMapping : parameterMappings) {
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) {
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
cacheKey.update(value);
}
}
//将environment.id到CacheKey对象中
if (configuration.getEnvironment() != null) {
// issue #176
cacheKey.update(configuration.getEnvironment().getId());
}
return cacheKey;
}
@Override
//判断一级缓存是否存在
public boolean isCached(MappedStatement ms, CacheKey key) {
return localCache.getObject(key) != null;
}
@Override
//提交
public void commit(boolean required) throws SQLException {
if (closed) {
throw new ExecutorException("Cannot commit, transaction is already closed");
}
//清空本地缓存
clearLocalCache();
//刷入批处理语句
flushStatements();
//是否要求提交事务,如果是,则提交事务
if (required) {
transaction.commit();
}
}
@Override
//回滚
public void rollback(boolean required) throws SQLException {
if (!closed) {
try {
//清空本地缓存
clearLocalCache();
//刷入批处理语句
flushStatements(true);
} finally {
if (required) {
transaction.rollback();
}
}
}
}
//清空一级缓存
@Override
public void clearLocalCache() {
if (!closed) {
//清理localCache
localCache.clear();
// 清理 localOutputParameterCache
localOutputParameterCache.clear();
}
}
protected abstract int doUpdate(MappedStatement ms, Object parameter)
throws SQLException;
protected abstract List<BatchResult> doFlushStatements(boolean isRollback)
throws SQLException;
//执行读操作,由子类实现
protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
throws SQLException;
//子类实现
protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)
throws SQLException;
protected void closeStatement(Statement statement) {
if (statement != null) {
try {
if (!statement.isClosed()) {
statement.close();
}
} catch (SQLException e) {
// ignore
}
}
}
/**
* Apply a transaction timeout.
* @param statement a current statement
* @throws SQLException if a database access error occurs, this method is called on a closed <code>Statement</code>
* @since 3.4.0
* @see StatementUtil#applyTransactionTimeout(Statement, Integer, Integer)
*/
protected void applyTransactionTimeout(Statement statement) throws SQLException {
StatementUtil.applyTransactionTimeout(statement, statement.getQueryTimeout(), transaction.getTimeout());
}
private void handleLocallyCachedOutputParameters(MappedStatement ms, CacheKey key, Object parameter, BoundSql boundSql) {
if (ms.getStatementType() == StatementType.CALLABLE) {
final Object cachedParameter = localOutputParameterCache.getObject(key);
if (cachedParameter != null && parameter != null) {
final MetaObject metaCachedParameter = configuration.newMetaObject(cachedParameter);
final MetaObject metaParameter = configuration.newMetaObject(parameter);
for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {
if (parameterMapping.getMode() != ParameterMode.IN) {
final String parameterName = parameterMapping.getProperty();
final Object cachedValue = metaCachedParameter.getValue(parameterName);
metaParameter.setValue(parameterName, cachedValue);
}
}
}
}
}
//真正访问数据库获取结果的方法
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
//在缓存中添加占位符号,和延迟加载有关。
localCache.putObject(key, EXECUTION_PLACEHOLDER);//在缓存中添加占位符
try {
//调用抽象方法doQuery,方法查询数据库并返回结果,可选的实现包括:simple、reuse、batch
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);//在缓存中删除占位符
}
localCache.putObject(key, list);//将真正的结果对象添加到一级缓存
if (ms.getStatementType() == StatementType.CALLABLE) {//如果是调用存储过程
localOutputParameterCache.putObject(key, parameter);//缓存输出类型结果参数
}
return list;
}
//获得Connection对象
protected Connection getConnection(Log statementLog) throws SQLException {
//获得Connection对象
Connection connection = transaction.getConnection();
if (statementLog.isDebugEnabled()) {
return ConnectionLogger.newInstance(connection, statementLog, queryStack);
} else {
return connection;
}
}
@Override
//设置包装器
public void setExecutorWrapper(Executor wrapper) {
this.wrapper = wrapper;
}
private static class DeferredLoad {
private final MetaObject resultObject;
private final String property;
private final Class<?> targetType;
private final CacheKey key;
private final PerpetualCache localCache;
private final ObjectFactory objectFactory;
private final ResultExtractor resultExtractor;
// issue #781
//延迟加载对象的构造函数
public DeferredLoad(MetaObject resultObject,
String property,
CacheKey key,
PerpetualCache localCache,
Configuration configuration,
Class<?> targetType) {
this.resultObject = resultObject;
this.property = property;
this.key = key;
this.localCache = localCache;
this.objectFactory = configuration.getObjectFactory();
this.resultExtractor = new ResultExtractor(configuration, objectFactory);
this.targetType = targetType;
}
//如果对象已经存在于缓存当中并且不是用占位符缓存的,就说明可以加载
public boolean canLoad() {
return localCache.getObject(key) != null && localCache.getObject(key) != EXECUTION_PLACEHOLDER;
}
//从缓存中加载相应的对象
public void load() {
@SuppressWarnings( "unchecked" )
// we suppose we get back a List
List<Object> list = (List<Object>) localCache.getObject(key);
Object value = resultExtractor.extractObjectFromList(list, targetType);
resultObject.setValue(property, value);
}
}
}