经过上一篇文章的我们应该对sqlsession的创建以及方法使用有所了解
- select类方法
- update/insert/delete方法
- commit()
- rollback()
- close()
接下来我们就来讲下sql的执行器是如何执行sql的,首先我们来普及下Executor,让大家对执行器稍微有点印象,让接下来的讲解更容易理解,不那么抽象。先让我们看两张图,刷个脸熟
- BaseExecutor为模板模式中的模板类。这个类在Executor接口实现中非常重要,其实现了Executor的大部分方法。他的子类只要实现三个方法即可,其中两个是doUpdate和doSelect方法,子类在实现这两个方法时直接操作数据库即可,其余的工作交由BaseExecutor完成。
- CachingExecutor是一个Executor的装饰器,给一个Executor增加了缓存的功能。
我们来看下Executor接口主要方法
public interface Executor {
//执行update/insert/delete
int update(MappedStatement ms, Object parameter) throws SQLException;
//执行查询
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds,
ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
//执行查询
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds,
ResultHandler resultHandler) 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();
void close(boolean forceRollback);
boolean isClosed();
void setExecutorWrapper(Executor executor);
}
接下来我们再来看看BaseExcutor模板是怎么实现Executor的
BaseExecutor有两个主要的属性:事务及本地缓存
protected BaseExecutor(Configuration configuration, Transaction transaction) {
//transaction,实现commit/rollback/close
this.transaction = transaction;
this.deferredLoads = new ConcurrentLinkedQueue<DeferredLoad>();
//本地缓存,也就是一级缓存
this.localCache = new PerpetualCache("LocalCache");
this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache");
this.closed = false;
this.configuration = configuration;
this.wrapper = this;
}
我们看下是如何查询和更新的
查询方法的实现
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds,
ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameter);
CacheKey key = this.createCacheKey(ms, parameter, rowBounds, boundSql);
return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
更新操作的实现
public int update(MappedStatement ms, Object parameter) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing an
update").object(ms.getId());
if(this.closed) {
throw new ExecutorException("Executor was closed.");
} else {
this.clearLocalCache();
return this.doUpdate(ms, parameter);
}
}
带缓存的查询实现
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 {
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;
}
和BaseExcutor平起平坐的还有一个执行器那就是CachingExecutor
具体数据库语句执行都是通过Excutor实现类去操作的,只是操作之前刷新本地缓存,和baseExcutor 区别不太大,感兴趣的可以下载源码看看
org.apache.ibatis.executor.CachingExecutor
public CachingExecutor(Executor delegate) {
//操作数据库的动作都是由这个Executor来完成的。
this.delegate = delegate;
delegate.setExecutorWrapper(this);
}