MyBatis设计模式深度解析(二)
一、MyBatis整体架构与设计模式续篇
在上一篇文章中,我们深入讲解了MyBatis中的构建者模式、工厂模式和代理模式。本文将继续探讨MyBatis中另外三种重要的设计模式:装饰器模式、模板方法模式和策略模式。这些设计模式的应用,使得MyBatis在功能扩展、性能优化和架构灵活性方面表现出色。
1.1 MyBatis整体架构回顾
MyBatis采用分层架构设计,从上到下包括:
- 应用层:用户应用程序
- 接口层:SqlSession、Mapper接口
- 核心处理层:SQL解析、执行、结果映射
- 基础支撑层:缓存、事务、类型处理、日志等
- 数据层:数据源、连接池、JDBC驱动
在本文中,我们将重点探讨装饰器模式、模板方法模式和策略模式在这些层次中的应用。 
1.2 本文涉及的设计模式
- 装饰器模式(Decorator Pattern):CachingExecutor、Cache装饰器链
- 模板方法模式(Template Method Pattern):BaseExecutor、BaseTypeHandler
- 策略模式(Strategy Pattern):RoutingStatementHandler、不同Executor策略
二、装饰器模式(Decorator Pattern)
装饰器模式是一种结构型设计模式,它允许你在不改变对象结构的情况下,动态地为对象添加新的行为。装饰器模式通过将对象包装在装饰器类中来实现功能的增强。
2.1 CachingExecutor
CachingExecutor是MyBatis中最典型的装饰器模式应用。它为Executor添加了二级缓存功能。
2.1.1 类定义
java
public class CachingExecutor implements Executor {
private final Executor delegate; // 被装饰的Executor
private final TransactionalCacheManager tcm = new TransactionalCacheManager();
public CachingExecutor(Executor delegate) {
this.delegate = delegate;
// 确保被装饰的Executor类型是SIMPLE、REUSE或BATCH
if (delegate instanceof CachingExecutor) {
throw new IllegalArgumentException("Cannot wrap a CachingExecutor");
}
}
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
// 1. 获取绑定SQL
BoundSql boundSql = ms.getBoundSql(parameterObject);
// 2. 创建缓存Key
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
// 3. 执行查询(先查缓存,缓存没有则查数据库)
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
// 4. 获取MappedStatement的缓存配置
Cache cache = ms.getCache();
if (cache != null) {
// 5. 刷新缓存(如果需要)
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
// 6. 确保参数不为null时才使用缓存
ensureNoOutParams(ms, boundSql);
// 7. 从事务缓存管理器获取缓存
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
// 8. 缓存未命中,委托给被装饰的Executor执行查询
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
// 9. 将查询结果放入缓存
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
// 10. 没有配置缓存,直接委托给被装饰的Executor
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
@Override
public int update(MappedStatement ms, Object parameterObject) throws SQLException {
// 更新操作先刷新缓存
flushCacheIfRequired(ms);
// 委托给被装饰的Executor执行更新
return delegate.update(ms, parameterObject);
}
private void flushCacheIfRequired(MappedStatement ms) {
Cache cache = ms.getCache();
if (cache != null && ms.isFlushCacheRequired()) {
tcm.clear(cache);
}
}
}

2.1.2 装饰器模式的优势
- 不修改原始类:通过包装而非继承来扩展功能
- 动态组合:可以在运行时动态地添加或删除功能
- 职责单一:每个装饰器只负责一个功能
- 灵活扩展:可以多层嵌套,实现功能的灵活组合
2.2 Cache装饰器链
MyBatis的缓存系统也大量使用了装饰器模式。Cache接口有多个装饰器实现,形成了一个装饰器链。
2.2.1 Cache接口
java
public interface Cache {
String getId();
void putObject(Object key, Object value);
Object getObject(Object key);
Object removeObject(Object key);
void clear();
int getSize();
ReadWriteLock getReadWriteLock();
}
2.2.2 Cache装饰器实现
java
// 1. PerpetualCache - 基础缓存实现
public class PerpetualCache implements Cache {
private final String id;
private Map<Object, Object> cache = new HashMap<>();
public PerpetualCache(String id) {
this.id = id;
}
@Override
public void putObject(Object key, Object value) {
cache.put(key, value);
}
@Override
public Object getObject(Object key) {
return cache.get(key);
}
@Override
public Object removeObject(Object key) {
return cache.remove(key);
}
@Override
public void clear() {
cache.clear();
}
}
// 2. LruCache - LRU淘汰策略装饰器
public class LruCache implements Cache {
private final Cache delegate;
private Map<Object, Object> keyMap;
private Object eldestKey;
public LruCache(Cache delegate) {
this.delegate = delegate;
setSize(1024);
}
@Override
public void putObject(Object key, Object value) {
delegate.putObject(key, value);
cycleKeyList(key);
}
@Override
public Object getObject(Object key) {
keyMap.get(key); // 触发LRU
return delegate.getObject(key);
}
private void cycleKeyList(Object key) {
keyMap.put(key, key);
if (eldestKey != null) {
delegate.removeObject(eldestKey);
eldestKey = null;
}
}
}
// 3. FifoCache - FIFO淘汰策略装饰器
public class FifoCache implements Cache {
private final Cache delegate;
private final Deque<Object> keyList;
private int size;
public FifoCache(Cache delegate) {
this.delegate = delegate;
this.keyList = new LinkedList<>();
this.size = 1024;
}
@Override
public void putObject(Object key, Object value) {
cycleKeyList(key);
delegate.putObject(key, value);
}
private void cycleKeyList(Object key) {
keyList.addLast(key);
if (keyList.size() > size) {
Object oldestKey = keyList.removeFirst();
delegate.removeObject(oldestKey);
}
}
}
// 4. SoftCache/WeakCache - 软引用/弱引用装饰器
public class SoftCache implements Cache {
private final Cache delegate;
private final Map<Object, Object> hardLinksToAvoidGarbageCollection;
@Override
public void putObject(Object key, Object value) {
delegate.putObject(key, new SoftEntry(value));
}
@Override
public Object getObject(Object key) {
Object value = delegate.getObject(key);
if (value instanceof SoftEntry) {
return ((SoftEntry) value).get();
}
return value;
}
}
// 5. BlockingCache - 阻塞装饰器(防止缓存击穿)
public class BlockingCache implements Cache {
private final Cache delegate;
private final ConcurrentHashMap<Object, CountDownLatch> locks;
@Override
public void putObject(Object key, Object value) {
try {
delegate.putObject(key, value);
} finally {
releaseLock(key);
}
}
@Override
public Object getObject(Object key) {
acquireLock(key);
Object value = delegate.getObject(key);
if (value != null) {
releaseLock(key);
}
return value;
}
private void acquireLock(Object key) {
CountDownLatch latch = new CountDownLatch(1);
CountDownLatch existing = locks.putIfAbsent(key, latch);
if (existing != null) {
try {
existing.await();
} catch (InterruptedException e) {
Thread.interrupted();
}
}
}
}
// 6. LoggingCache - 日志装饰器
public class LoggingCache implements Cache {
private final Cache delegate;
private int hits = 0;
private int requests = 0;
@Override
public void putObject(Object key, Object value) {
delegate.putObject(key, value);
}
@Override
public Object getObject(Object key) {
requests++;
final Object value = delegate.getObject(key);
if (value != null) {
hits++;
}
if (log.isDebugEnabled()) {
log.debug("Cache Hit Ratio [" + getId() + "]: " + getHitRatio());
}
return value;
}
private double getHitRatio() {
return (double) hits / (double) requests;
}
}
// 7. ScheduledCache - 定时清理装饰器
public class ScheduledCache implements Cache {
private final Cache delegate;
private long clearInterval;
private long lastClear;
@Override
public void putObject(Object key, Object value) {
clearWhenStale();
delegate.putObject(key, value);
}
@Override
public Object getObject(Object key) {
return clearWhenStale() ? null : delegate.getObject(key);
}
private boolean clearWhenStale() {
if (System.currentTimeMillis() - lastClear > clearInterval) {
clear();
return true;
}
return false;
}
}
// 8. SerializedCache - 序列化装饰器
public class SerializedCache implements Cache {
private final Cache delegate;
@Override
public void putObject(Object key, Object value) {
if (value != null && !(value instanceof Serializable)) {
throw new CacheException("Cacheed object is not serializable: " + value);
}
delegate.putObject(key, serialize(value));
}
@Override
public Object getObject(Object key) {
Object object = delegate.getObject(key);
return object == null ? null : deserialize((byte[]) object);
}
}
// 9. SynchronizedCache - 同步装饰器
public class SynchronizedCache implements Cache {
private final Cache delegate;
@Override
public synchronized void putObject(Object key, Object value) {
delegate.putObject(key, value);
}
@Override
public synchronized Object getObject(Object key) {
return delegate.getObject(key);
}
@Override
public synchronized void clear() {
delegate.clear();
}
}
// 10. TransactionalCache - 事务缓存装饰器
public class TransactionalCache implements Cache {
private final Cache delegate;
private boolean clearOnCommit;
private Map<Object, Object> entriesToAddOnCommit;
@Override
public void putObject(Object key, Object value) {
entriesToAddOnCommit.put(key, value);
}
@Override
public Object getObject(Object key) {
if (clearOnCommit) {
return null;
}
return delegate.getObject(key);
}
public void commit() {
if (clearOnCommit) {
delegate.clear();
}
for (Map.Entry<Object, Object> entry : entriesToAddOnCommit.entrySet()) {
delegate.putObject(entry.getKey(), entry.getValue());
}
reset();
}
}

2.2.3 Cache装饰器链的构建
java
public class CacheBuilder {
private String id;
private Class<? extends Cache> implementation;
private List<Class<? extends Cache>> decorators;
public Cache build() {
setDefaultImplementations();
Cache cache = newBaseCacheInstance(implementation, id);
setCacheProperties(cache);
// 应用装饰器
for (Class<? extends Cache> decorator : decorators) {
cache = newCacheDecoratorInstance(decorator, cache);
setCacheProperties(cache);
}
return cache;
}
}
2.3 装饰器模式的应用场景
在MyBatis中,装饰器模式主要应用于:
- Executor增强:CachingExecutor为Executor添加二级缓存功能
- Cache功能扩展:通过各种Cache装饰器添加LRU、FIFO、日志等功能
- StatementHandler增强:通过RoutingStatementHandler路由到不同的实现
2.4 装饰器模式 vs 继承
装饰器模式相比继承的优势:
| 对比项 | 装饰器模式 | 继承 |
|---|---|---|
| 扩展方式 | 动态组合 | 静态继承 |
| 灵活性 | 高 | 低 |
| 代码复用 | 好 | 一般 |
| 类数量 | 可能增加 | 可能爆炸 |
| 复杂度 | 中等 | 简单 |
三、模板方法模式(Template Method Pattern)
模板方法模式是一种行为型设计模式,它在父类中定义了一个算法的框架,允许子类在不改变算法结构的情况下重写算法的特定步骤。
3.1 BaseExecutor
BaseExecutor是MyBatis中模板方法模式的典型应用,它定义了SQL执行的基本流程,将具体的执行逻辑留给子类实现。
3.1.1 BaseExecutor核心代码
java
public abstract class BaseExecutor implements Executor {
protected Transaction transaction;
protected Executor wrapper;
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
// 1. 获取绑定SQL
BoundSql boundSql = ms.getBoundSql(parameter);
// 2. 创建缓存Key
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
// 3. 调用模板方法
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
// 模板方法 - 定义算法骨架
@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) {
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
// 4. 检查一级缓存
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
// 5. 缓存未命中,调用抽象方法查询数据库
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
deferLoadIfNeeded();
}
return list;
}
// 从数据库查询 - 也是模板方法
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 {
// 6. 调用抽象方法,由子类实现具体查询逻辑
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
localCache.putObject(key, list);
return list;
}
// 抽象方法 - 由子类实现具体的查询逻辑
protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter,
RowBounds rowBounds, ResultHandler resultHandler,
BoundSql boundSql) throws SQLException;
// 抽象方法 - 由子类实现具体的更新逻辑
protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException;
// 其他抽象方法...
}
3.1.2 BaseExecutor的子类实现
java
// 1. SimpleExecutor - 简单执行器
public class SimpleExecutor extends BaseExecutor {
@Override
protected <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
// 1. 创建Statement
stmt = createStatement(ms, parameter, rowBounds);
// 2. 设置参数
setStatementParameters(ms, stmt, parameter, rowBounds, boundSql);
// 3. 执行查询
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
@Override
protected 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);
}
}
}
// 2. ReuseExecutor - 重用执行器
public class ReuseExecutor extends BaseExecutor {
private final Map<String, Statement> statementMap = new HashMap<>();
@Override
protected <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, rowBounds, resultHandler, boundSql);
Statement stmt = prepareStatement(handler, ms.getStatementLog(), true);
return handler.query(stmt, resultHandler);
}
private Statement prepareStatement(StatementHandler handler, Log statementLog, boolean isReusable) throws SQLException {
BoundSql boundSql = handler.getBoundSql();
String sql = boundSql.getSql();
Statement stmt;
if (isReusable) {
// 尝试重用Statement
stmt = statementMap.get(sql);
if (stmt == null) {
stmt = handler.prepare(statementLog.getConnection(), transaction.getTimeout());
statementMap.put(sql, stmt);
}
} else {
stmt = handler.prepare(statementLog.getConnection(), transaction.getTimeout());
}
handler.parameterize(stmt);
return stmt;
}
}
// 3. BatchExecutor - 批量执行器
public class BatchExecutor extends BaseExecutor {
private final List<Statement> statementList = new ArrayList<>();
private final List<BatchResult> batchResultList = new ArrayList<>();
@Override
protected int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
Statement stmt = prepareStatement(handler, ms.getStatementLog());
handler.parameterize(stmt);
batchResultList.add(new BatchResult(ms.getStatement(), ms.getId(), parameter));
handler.batch(stmt);
return BATCH_UPDATE_RETURN_VALUE;
}
@Override
public List<BatchResult> doFlushStatements(boolean isRollback) {
List<BatchResult> results = new ArrayList<>();
try {
for (int i = 0, n = statementList.size(); i < n; i++) {
Statement stmt = statementList.get(i);
BatchResult batchResult = batchResultList.get(i);
try {
int[] updateCounts = stmt.executeBatch();
batchResult.setUpdateCounts(updateCounts);
results.add(batchResult);
} catch (BatchUpdateException e) {
StringBuilder message = new StringBuilder();
message.append(batchResult.getStatement()).append(" failed.");
if (updateCounts != null && updateCounts.length > 0) {
message.append(" Update counts: ");
for (int j = 0; j < updateCounts.length; j++) {
message.append(updateCounts[j]).append(";");
}
}
throw new BatchExecutorException(message.toString(), e, updateCounts, batchResult.getStatement());
}
}
return results;
} finally {
clearLocalCache();
statementList.clear();
batchResultList.clear();
}
}
}

3.2 BaseTypeHandler
BaseTypeHandler也是模板方法模式的应用,它定义了类型处理的基本流程。
3.2.1 BaseTypeHandler核心代码
java
public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
// 模板方法:设置非空参数
setParameter(ps, i, parameter, jdbcType);
}
@Override
public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
// 模板方法:通过列名获取结果
T result = getNullableResult(rs, columnName);
return rs.wasNull() ? null : result;
}
@Override
public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
// 模板方法:通过列索引获取结果
T result = getNullableResult(rs, columnIndex);
return rs.wasNull() ? null : result;
}
@Override
public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
// 模板方法:从存储过程获取结果
T result = getNullableResult(cs, columnIndex);
return cs.wasNull() ? null : result;
}
// 抽象方法:由子类实现具体的参数设置逻辑
public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
// 抽象方法:由子类实现具体的结果获取逻辑
public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException;
public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException;
public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException;
}
3.2.2 具体的TypeHandler实现
java
// StringTypeHandler
public class StringTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter);
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
return rs.getString(columnName);
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return rs.getString(columnIndex);
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return cs.getString(columnIndex);
}
}
// IntegerTypeHandler
public class IntegerTypeHandler extends BaseTypeHandler<Integer> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Integer parameter, JdbcType jdbcType) throws SQLException {
ps.setInt(i, parameter);
}
@Override
public Integer getNullableResult(ResultSet rs, String columnName) throws SQLException {
return rs.getInt(columnName);
}
@Override
public Integer getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return rs.getInt(columnIndex);
}
@Override
public Integer getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return cs.getInt(columnIndex);
}
}
3.3 模板方法模式的优势
- 代码复用:将公共逻辑提取到父类,避免重复代码
- 扩展性强:子类可以灵活实现特定步骤
- 算法稳定:算法框架固定,保证一致性
- 易于维护:修改算法只需修改父类
四、策略模式(Strategy Pattern)
策略模式是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。策略模式让算法独立于使用它的客户端。
4.1 RoutingStatementHandler
RoutingStatementHandler是MyBatis中策略模式的典型应用,它根据MappedStatement的配置,路由到不同的StatementHandler实现。
4.1.1 RoutingStatementHandler源码
java
public class RoutingStatementHandler implements StatementHandler {
private final StatementHandler delegate;
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// 根据Statement类型选择策略
switch (ms.getStatementType()) {
case STATEMENT:
delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}
}
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
return delegate.prepare(connection, transactionTimeout);
}
@Override
public void parameterize(Statement statement) throws SQLException {
delegate.parameterize(statement);
}
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
return delegate.query(statement, resultHandler);
}
@Override
public int update(Statement statement) throws SQLException {
return delegate.update(statement);
}
// 其他方法都委托给delegate...
}
4.1.2 三种StatementHandler策略
java
// 1. SimpleStatementHandler - 简单SQL策略
public class SimpleStatementHandler extends BaseStatementHandler {
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
if (mappedStatement.getResultSetType() == ResultSetType.FORWARD_ONLY) {
return connection.createStatement();
} else {
return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
@Override
public int update(Statement statement) throws SQLException {
String sql = boundSql.getSql();
Object parameterObject = boundSql.getParameterObject();
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
int rows;
if (keyGenerator instanceof Jdbc3KeyGenerator) {
statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
rows = statement.getUpdateCount();
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else if (keyGenerator instanceof SelectKeyGenerator) {
statement.execute(sql);
rows = statement.getUpdateCount();
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else {
statement.execute(sql);
rows = statement.getUpdateCount();
}
return rows;
}
}
// 2. PreparedStatementHandler - 预编译SQL策略
public class PreparedStatementHandler extends BaseStatementHandler {
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = boundSql.getSql();
if (mappedStatement.getResultSetType() == ResultSetType.FORWARD_ONLY) {
return connection.prepareStatement(sql);
} else {
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
@Override
public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}
@Override
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;
}
}
// 3. CallableStatementHandler - 存储过程策略
public class CallableStatementHandler extends BaseStatementHandler {
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = boundSql.getSql();
if (mappedStatement.getResultSetType() == ResultSetType.FORWARD_ONLY) {
return connection.prepareCall(sql);
} else {
return connection.prepareCall(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
@Override
public void parameterize(Statement statement) throws SQLException {
registerOutputParameters((CallableStatement) statement);
parameterHandler.setParameters((CallableStatement) statement);
}
@Override
public int update(Statement statement) throws SQLException {
CallableStatement cs = (CallableStatement) statement;
cs.execute();
int rows = cs.getUpdateCount();
Object parameterObject = boundSql.getParameterObject();
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
keyGenerator.processAfter(executor, mappedStatement, cs, parameterObject);
return rows;
}
}
public class Configuration {
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
Executor executor;
// 根据ExecutorType选择策略
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);
}
return (Executor) interceptorChain.pluginAll(executor);
}
}
4.2.2 三种Executor策略对比
| Executor类型 | 特点 | 适用场景 | 性能 |
|---|---|---|---|
| SimpleExecutor | 每次执行创建新Statement | 一般查询、单条操作 | 中等 |
| ReuseExecutor | 重用Statement | 执行相同SQL多次 | 较好 |
| BatchExecutor | 批量执行SQL | 批量插入、更新 | 最好 |

4.3 策略模式的优势
- 算法可替换:可以灵活切换不同的算法实现
- 代码解耦:算法的实现与使用分离
- 扩展方便:新增策略只需实现新类
- 简化测试:可以独立测试每个策略
4.4 策略模式 vs 模板方法模式
| 对比项 | 策略模式 | 模板方法模式 |
|---|---|---|
| 算法结构 | 可变 | 固定 |
| 实现方式 | 组合 | 继承 |
| 灵活性 | 高 | 中等 |
| 复杂度 | 较高 | 较低 |
五、设计模式的综合应用
在MyBatis中,多种设计模式往往协同工作,共同完成复杂的功能。
5.1 Executor的创建过程
java
// 1. 模板方法模式:BaseExecutor定义执行流程
// 2. 策略模式:根据ExecutorType选择SimpleExecutor、ReuseExecutor或BatchExecutor
// 3. 装饰器模式:CachingExecutor为Executor添加缓存功能
// 4. 代理模式:Plugin为Executor添加拦截功能
Executor executor = configuration.newExecutor(transaction, ExecutorType.SIMPLE);
5.2 Cache的构建过程
java
// 1. 装饰器模式:多层Cache装饰器嵌套
// 2. 模板方法模式:BaseExecutor定义查询流程(使用缓存)
Cache cache = new CacheBuilder("myCache")
.implementation(PerpetualCache.class)
.addDecorator(LruCache.class)
.addDecorator(FifoCache.class)
.addDecorator(ScheduledCache.class)
.build();
5.3 StatementHandler的选择过程
java
// 1. 策略模式:RoutingStatementHandler路由到不同的StatementHandler
// 2. 模板方法模式:BaseStatementHandler定义Statement处理流程
// 3. 代理模式:LoggerStatementHandler添加日志功能
StatementHandler handler = configuration.newStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);

六、最佳实践与建议
6.1 装饰器模式应用场景
当满足以下条件时,可以考虑使用装饰器模式:
- 需要动态地、透明地给对象添加功能
- 不希望通过继承来扩展功能(避免类爆炸)
- 需要组合多个功能
应用示例:
java
// 为服务添加缓存、日志、监控功能
Service service = new LoggingService(
new MonitoringService(
new CachingService(
new BasicService()
)
)
);
6.2 模板方法模式应用场景
当满足以下条件时,可以考虑使用模板方法模式:
- 算法的整体结构固定,部分步骤可变
- 多个子类有共同的行为逻辑
- 需要控制子类的扩展
应用示例:
java
public abstract class AbstractDataService {
// 模板方法:定义数据处理流程
public final void processData(String data) {
validate(data); // 验证
data = transform(data); // 转换
save(data); // 保存
}
protected abstract void validate(String data);
protected abstract String transform(String data);
protected abstract void save(String data);
}
6.3 策略模式应用场景
当满足以下条件时,可以考虑使用策略模式:
- 有多种算法可以相互替换
- 算法的使用和实现分离
- 需要在运行时选择算法
应用示例:
java
// 支付策略
public interface PaymentStrategy {
void pay(int amount);
}
public class CreditCardPayment implements PaymentStrategy {
public void pay(int amount) {
// 信用卡支付逻辑
}
}
public class WeChatPayPayment implements PaymentStrategy {
public void pay(int amount) {
// 微信支付逻辑
}
}
// 上下文
public class PaymentContext {
private PaymentStrategy strategy;
public void setPaymentStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void processPayment(int amount) {
strategy.pay(amount);
}
}
6.4 设计模式选择指南
| 场景 | 推荐模式 | 理由 |
|---|---|---|
| 需要动态添加功能 | 装饰器模式 | 灵活组合,避免继承 |
| 算法结构固定部分可变 | 模板方法模式 | 代码复用,结构清晰 |
| 算法需要相互替换 | 策略模式 | 解耦算法和使用 |
| 创建复杂对象 | 构建者模式 | 分步构建,代码清晰 |
| 创建对象族 | 工厂模式 | 解耦创建和使用 |
| 控制对象访问 | 代理模式 | 增强功能,不修改原类 |
6.5 避免过度设计
虽然设计模式很有用,但也要避免过度设计:
- 简单问题简单解决:不要为了使用模式而使用模式
- 按需设计:根据实际需求选择合适的模式
- 保持简洁:简单的设计往往比复杂的设计更好
- 重构时再引入:先实现功能,重构时再应用模式
七、总结
本文深入讲解了MyBatis中的装饰器模式、模板方法模式和策略模式,通过源码分析和示例代码,帮助读者理解这些设计模式在实际框架中的应用。
7.1 关键要点
装饰器模式:
- CachingExecutor为Executor添加二级缓存功能
- Cache装饰器链提供LRU、FIFO、日志等多种功能
- 动态组合,灵活扩展
模板方法模式:
- BaseExecutor定义SQL执行的基本流程
- BaseTypeHandler定义类型处理的基本流程
- 代码复用,算法稳定
策略模式:
- RoutingStatementHandler根据配置路由到不同的StatementHandler
- 不同Executor策略适用于不同的执行场景
- 算法可替换,代码解耦
7.2 设计模式的价值
- 提高代码质量:使代码更易读、易维护、易扩展
- 促进架构设计:提供成熟的设计思想和解决方案
- 增强团队协作:统一的设计语言和思维方式
- 提升个人能力:深入理解设计模式是成为高级工程师的必经之路
。