手写Mybatis:第20章-Mybatis 框架源码10种设计模式分析

文章目录

  • 一、类型:创建型模式
    • 1.1 工厂模式
    • 1.2 单例模式
    • 1.3 建造者模式
  • 二、类型:结构型模式
    • 2.1 适配器模式
    • 2.2 代理模式
    • 2.3 组合模式
    • 2.4 装饰器模式
  • 三、类型:行为型模式
    • 3.1 模板模式
    • 3.2 策略模式
    • 3.3 迭代器模式

在这里插入图片描述

一、类型:创建型模式

1.1 工厂模式

SqlSessionFactory.java

package com.lino.mybatis.session;/*** @description: 工厂模式接口,构建SqlSession的工厂*/
public interface SqlSessionFactory {/*** 打开一个session** @return SqlSession*/SqlSession openSession();
}

DefaultSqlSessionFactory.java

package com.lino.mybatis.session.defaults;import com.lino.mybatis.executor.Executor;
import com.lino.mybatis.mapping.Environment;
import com.lino.mybatis.session.Configuration;
import com.lino.mybatis.session.SqlSession;
import com.lino.mybatis.session.SqlSessionFactory;
import com.lino.mybatis.session.TransactionIsolationLevel;
import com.lino.mybatis.transaction.Transaction;
import com.lino.mybatis.transaction.TransactionFactory;
import java.sql.SQLException;/*** @description: 默认的SqlSessionFactory实现类*/
public class DefaultSqlSessionFactory implements SqlSessionFactory {private final Configuration configuration;public DefaultSqlSessionFactory(Configuration configuration) {this.configuration = configuration;}@Overridepublic SqlSession openSession() {Transaction tx = null;try {final Environment environment = configuration.getEnvironment();TransactionFactory transactionFactory = environment.getTransactionFactory();tx = transactionFactory.newTransaction(configuration.getEnvironment().getDataSource(), TransactionIsolationLevel.READ_COMMITTED, false);// 创建执行器final Executor executor = configuration.newExecutor(tx);// 创建 DefaultSqlSessionreturn new DefaultSqlSession(configuration, executor);} catch (Exception e) {try {assert tx != null;tx.close();} catch (SQLException ignore) {}throw new RuntimeException("Error opening session. Cause: " + e);}}
}

在这里插入图片描述

  • 工厂模式:简单工厂,是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类决定实例对象的类型。
  • 场景介绍SqlSessionFactory 是获取会话的工厂,每次我们使用 Mybatis 操作数据库的时候,都会开启一个新的会话。
    • 在会话工厂的实现中负责获取数据源环境配置信息、构建事务工厂、创建操作 SQL 的执行器,并最终返回会话实现类。
  • 同类设计SqlSessionFactoryObjectFactoryMapperproxyFactoryDataSourceFactory

1.2 单例模式

Configuration.java

package com.lino.mybatis.session;import com.lino.mybatis.binding.MapperRegistry;
import com.lino.mybatis.cache.Cache;
import com.lino.mybatis.cache.decorators.FifoCache;
import com.lino.mybatis.cache.impl.PerpetualCache;
import com.lino.mybatis.datasource.druid.DruidDataSourceFactory;
import com.lino.mybatis.datasource.pooled.PooledDataSourceFactory;
import com.lino.mybatis.datasource.unpooled.UnpooledDataSourceFactory;
import com.lino.mybatis.executor.CachingExecutor;
import com.lino.mybatis.executor.Executor;
import com.lino.mybatis.executor.SimpleExecutor;
import com.lino.mybatis.executor.keygen.KeyGenerator;
import com.lino.mybatis.executor.parameter.ParameterHandler;
import com.lino.mybatis.executor.resultset.DefaultResultSetHandler;
import com.lino.mybatis.executor.resultset.ResultSetHandler;
import com.lino.mybatis.executor.statement.PreparedStatementHandler;
import com.lino.mybatis.executor.statement.StatementHandler;
import com.lino.mybatis.mapping.BoundSql;
import com.lino.mybatis.mapping.Environment;
import com.lino.mybatis.mapping.MappedStatement;
import com.lino.mybatis.mapping.ResultMap;
import com.lino.mybatis.plugin.Interceptor;
import com.lino.mybatis.plugin.InterceptorChain;
import com.lino.mybatis.reflection.MetaObject;
import com.lino.mybatis.reflection.factory.DefaultObjectFactory;
import com.lino.mybatis.reflection.factory.ObjectFactory;
import com.lino.mybatis.reflection.wrapper.DefaultObjectWrapperFactory;
import com.lino.mybatis.reflection.wrapper.ObjectWrapperFactory;
import com.lino.mybatis.scripting.LanguageDriver;
import com.lino.mybatis.scripting.LanguageDriverRegistry;
import com.lino.mybatis.scripting.xmltags.XMLLanguageDriver;
import com.lino.mybatis.transaction.Transaction;
import com.lino.mybatis.transaction.jdbc.JdbcTransactionFactory;
import com.lino.mybatis.type.TypeAliasRegistry;
import com.lino.mybatis.type.TypeHandlerRegistry;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;/*** @description: 配置项*/
public class Configuration {/*** 环境*/protected Environment environment;/*** 是否使用自动生成键值对*/protected boolean useGeneratedKeys = false;/*** 默认启用缓存,cacheEnabled = true/false*/protected boolean cacheEnabled = true;/*** 缓存机制,默认不配置的情况是 SESSION*/protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;/*** 映射注册机*/protected MapperRegistry mapperRegistry = new MapperRegistry(this);/*** 映射的语句,存在Map里*/protected final Map<String, MappedStatement> mappedStatements = new HashMap<>(16);/*** 缓存,存在Map里*/protected final Map<String, Cache> caches = new HashMap<>(16);/*** 结果映射,存在Map里*/protected final Map<String, ResultMap> resultMaps = new HashMap<>(16);/*** 键值生成器,存在Map里*/protected final Map<String, KeyGenerator> keyGenerators = new HashMap<>(16);/*** 插件拦截器链*/protected final InterceptorChain interceptorChain = new InterceptorChain();/*** 类型别名注册机*/protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();/*** 脚本语言注册器*/protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();/*** 类型处理器注册机*/protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();/*** 对象工厂*/protected ObjectFactory objectFactory = new DefaultObjectFactory();/*** 对象包装工厂*/protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();/*** 准备资源列表*/protected final Set<String> loadedResources = new HashSet<>();/*** 数据库ID*/protected String databaseId;//...}

在这里插入图片描述

  • 单例模式:是一种创建型模式,让你能够保证一个类只有一个实例,并提供一个访问该实例的全局节点。
  • 场景介绍Configuration 就像狗皮膏药一样大单例,贯穿整个会话的生命周期,所有的配置对象。
    • 映射、缓存、入参、出参、拦截器、注册机、对象工厂等,都在 Configuration 配置项中初始化。
    • 并随着 SqlSessionFactorybuilder 构建阶段完成实例化操作。
  • 同类场景ErrorContextLogFactoryConfigutation

1.3 建造者模式

ResultMap.java

package com.lino.mybatis.mapping;import com.lino.mybatis.session.Configuration;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;/*** @description: 结果映射*/
public class ResultMap {private String id;private Class<?> type;private List<ResultMapping> resultMappings;private Set<String> mappedColumns;public ResultMap() {}public static class Builder {private ResultMap resultMap = new ResultMap();public Builder(Configuration configuration, String id, Class<?> type, List<ResultMapping> resultMappings) {resultMap.id = id;resultMap.type = type;resultMap.resultMappings = resultMappings;}public ResultMap build() {resultMap.mappedColumns = new HashSet<>();// 添加 mappedColums 字段for (ResultMapping resultMapping : resultMap.resultMappings) {final String column = resultMapping.getColumn();if (column != null) {resultMap.mappedColumns.add(column.toUpperCase(Locale.ENGLISH));}}return resultMap;}}//...
}

在这里插入图片描述

  • 建造者模式:使用多个简单的对象一步一步构建成一个复杂的对象,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
  • 场景介绍:关于建造者模式在 Mybatis 框架里的使用,到处都是 XxxBuilder,所有关于 XML 文件的解析到各类对象的封装,都使用建造者以及建造者助手来完成对象的封装。
    • 它的核心目的就是不希望把过多的关于对象的属性设置,写到其他业务流程中,而是用创建者的方式提供最佳的边界隔离。
  • 同类场景SqlSesiionFactoryBuilderXMLConfigBuilderXMLMapperBuilderXMLStatementBuilderCacheBuilder

二、类型:结构型模式

2.1 适配器模式

Log.java

package com.lino.mybatis.logging;/*** @description: 日志接口*/
public interface Log {boolean isDebugEnabled();boolean isTraceEnabled();void error(String s, Throwable e);void error(String s);void debug(String s);void trace(String s);void warn(String s);
}

Slf4jImpl.java

package com.lino.mybatis.logging.slf4j;import com.lino.mybatis.logging.Log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** @description: slf4j log 设计模式类,不做实现*/
public class Slf4jImpl implements Log {public Slf4jImpl(String clazz) {Logger logger = LoggerFactory.getLogger(clazz);}@Overridepublic boolean isDebugEnabled() {return false;}@Overridepublic boolean isTraceEnabled() {return false;}@Overridepublic void error(String s, Throwable e) {}@Overridepublic void error(String s) {}@Overridepublic void debug(String s) {}@Overridepublic void trace(String s) {}@Overridepublic void warn(String s) {}
}

在这里插入图片描述

  • 适配器模式:是一种结构型设计模式,它能使接口不兼容的对象能够相互合作。
  • 场景介绍:正是因为有太多的日志框架,包括:Log4j、Log4j2、Slf4J 等等,而这些日志框架的使用接口又都各有差异,为了统一这些日志工具的接口,Mybatis 定义了一套统一的日志接口,为所有的其他日志工具接口做相应的适配操作。
  • 同类场景:主要集中在对日志的适配上,Log 和 对应的实现类,以及在 LogFactory 工厂方法中进行使用。

2.2 代理模式

MapperProxy.java

package com.lino.mybatis.binding;import com.lino.mybatis.session.SqlSession;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;/*** @description: 映射器代理类*/
public class MapperProxy<T> implements InvocationHandler, Serializable {private static final long serialVersionUID = -6424540398559729838L;private SqlSession sqlSession;private final Class<T> mapperInterface;private final Map<Method, MapperMethod> methodCache;public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {this.sqlSession = sqlSession;this.mapperInterface = mapperInterface;this.methodCache = methodCache;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (Object.class.equals(method.getDeclaringClass())) {return method.invoke(this, args);} else {final MapperMethod mapperMethod = cacheMapperMethod(method);return mapperMethod.execute(sqlSession, args);}}/*** 去缓存中找MapperMethod*/private MapperMethod cacheMapperMethod(Method method) {MapperMethod mapperMethod = methodCache.get(method);if (mapperMethod == null) {mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());methodCache.put(method, mapperMethod);}return mapperMethod;}
}

在这里插入图片描述

  • 代理模式:是一种结构型模式,让你能够提供对象的替代品或其占位符。代理控制着对原对象的访问,并允许在将请求提交给对象前进行一些处理。
  • 场景介绍:没有代理模式,就不会有各类的框架存在。就像 Mybatis 中的 MybatisProxy 映射器代理实现类,它所实现的功能就是帮助我们完成 DAO 接口的具体实现类的方法操作,你的任何一个配置的 DAO 接口所调用的 CRUD 方法,都会被 MapperProxy 接管,调用到方法执行器等一系列操作,并返回最终的数据的数据库执行结果。
  • 同类场景DriverProxyPluginInvokerMapperProxy

2.3 组合模式

SqlNode.java

package com.lino.mybatis.scripting.xmltags;/*** @description: SQL 节点*/
public interface SqlNode {/*** 应用动态上下文** @param context 动态上下文* @return boolean*/boolean apply(DynamicContext context);
}

IfSqlNode.java

package com.lino.mybatis.scripting.xmltags;/*** @description: IF SQL 节点*/
public class IfSqlNode implements SqlNode {private ExpressionEvaluator evaluator;private String test;private SqlNode contents;public IfSqlNode(SqlNode contents, String test) {this.test = test;this.contents = contents;this.evaluator = new ExpressionEvaluator();}@Overridepublic boolean apply(DynamicContext context) {// 如果满足条件,则apply,并返回trueif (evaluator.evaluateBoolean(test, context.getBindings())) {contents.apply(context);return true;}return false;}
}

XMLScriptBuilder.java

package com.lino.mybatis.scripting.xmltags;import com.lino.mybatis.builder.BaseBuilder;
import com.lino.mybatis.mapping.SqlSource;
import com.lino.mybatis.scripting.defaults.RawSqlSource;
import com.lino.mybatis.session.Configuration;
import org.dom4j.Element;
import org.dom4j.Node;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @description: XML脚本构建器*/
public class XMLScriptBuilder extends BaseBuilder {private Element element;private boolean isDynamic;private Class<?> parameterType;private final Map<String, NodeHandler> nodeHandlerMap = new HashMap<>();public XMLScriptBuilder(Configuration configuration, Element element, Class<?> parameterType) {super(configuration);this.element = element;this.parameterType = parameterType;initNodeHandlerMap();}private void initNodeHandlerMap() {// 9种,实现其中2种 trim/where/set/foreach/if/choose/when/otherwise/bindnodeHandlerMap.put("trim", new TrimHandler());nodeHandlerMap.put("if", new IfHandler());}public SqlSource parseScriptNode() {List<SqlNode> contents = parseDynamicTags(element);MixedSqlNode rootSqlNode = new MixedSqlNode(contents);SqlSource sqlSource = null;if (isDynamic) {sqlSource = new DynamicSqlSource(configuration, rootSqlNode);} else {sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType);}return sqlSource;}private List<SqlNode> parseDynamicTags(Element element) {List<SqlNode> contents = new ArrayList<>();List<Node> children = element.content();for (Node child : children) {if (child.getNodeType() == Node.TEXT_NODE || child.getNodeType() == Node.CDATA_SECTION_NODE) {String data = child.getText();TextSqlNode textSqlNode = new TextSqlNode(data);if (textSqlNode.isDynamic()) {contents.add(textSqlNode);isDynamic = true;} else {contents.add(new StaticTextSqlNode(data));}} else if (child.getNodeType() == Node.ELEMENT_NODE) {String nodeName = child.getName();NodeHandler handler = nodeHandlerMap.get(nodeName);if (handler == null) {throw new RuntimeException("Unknown element <" + nodeName + "> in SQL statement.");}handler.handleNode(element.element(child.getName()), contents);isDynamic = true;}}return contents;}private interface NodeHandler {void handleNode(Element nodeToHandle, List<SqlNode> targetContents);}private class TrimHandler implements NodeHandler {@Overridepublic void handleNode(Element nodeToHandle, List<SqlNode> targetContents) {List<SqlNode> contents = parseDynamicTags(nodeToHandle);MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);String prefix = nodeToHandle.attributeValue("prefix");String prefixOverrides = nodeToHandle.attributeValue("prefixOverrides");String suffix = nodeToHandle.attributeValue("suffix");String suffixOverrides = nodeToHandle.attributeValue("suffixOverrides");TrimSqlNode trim = new TrimSqlNode(configuration, mixedSqlNode, prefix, prefixOverrides, suffix, suffixOverrides);targetContents.add(trim);}}private class IfHandler implements NodeHandler {@Overridepublic void handleNode(Element nodeToHandle, List<SqlNode> targetContents) {List<SqlNode> contents = parseDynamicTags(nodeToHandle);MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);String test = nodeToHandle.attributeValue("test");IfSqlNode ifSqlNode = new IfSqlNode(mixedSqlNode, test);targetContents.add(ifSqlNode);}}
}

Activity_Mapper.xml

<select id="queryActivityById" parameterType="com.lino.mybatis.test.po.Activity" resultMap="activityMap">SELECT activity_id, activity_name, activity_desc, create_time, update_timeFROM activity<trim prefix="where" prefixOverrides="AND | OR" suffixOverrides="and"><if test="null != activityId">activity_id = #{activityId}</if></trim>
</select>

在这里插入图片描述

  • 组合模式:是一种结构型设计模式,你可以使用它将对象组合成树状结构,并且能独立使用对象一样使用它们。
  • 场景介绍:在 Mybatis XML 动态的 SQL 配置中,共提供了9种(trim/where/set/foreach/if/choose/when/otherwise/bind)标签的使用,让使用者可以组合出各类场景的 SQL 语句。而 SqlNode 接口的实现就是每一个组合结构种的规则节点,通过规则节点的组装完成一颗规则树组合模式的使用。
  • 同类场景:主要体现在对各类 SQL 标签的解析上,以实现 SqlNode 接口的各个子类为主。

2.4 装饰器模式

Congiguration.java

package com.lino.mybatis.session;import com.lino.mybatis.binding.MapperRegistry;
import com.lino.mybatis.cache.Cache;
import com.lino.mybatis.cache.decorators.FifoCache;
import com.lino.mybatis.cache.impl.PerpetualCache;
import com.lino.mybatis.datasource.druid.DruidDataSourceFactory;
import com.lino.mybatis.datasource.pooled.PooledDataSourceFactory;
import com.lino.mybatis.datasource.unpooled.UnpooledDataSourceFactory;
import com.lino.mybatis.executor.CachingExecutor;
import com.lino.mybatis.executor.Executor;
import com.lino.mybatis.executor.SimpleExecutor;
import com.lino.mybatis.executor.keygen.KeyGenerator;
import com.lino.mybatis.executor.parameter.ParameterHandler;
import com.lino.mybatis.executor.resultset.DefaultResultSetHandler;
import com.lino.mybatis.executor.resultset.ResultSetHandler;
import com.lino.mybatis.executor.statement.PreparedStatementHandler;
import com.lino.mybatis.executor.statement.StatementHandler;
import com.lino.mybatis.mapping.BoundSql;
import com.lino.mybatis.mapping.Environment;
import com.lino.mybatis.mapping.MappedStatement;
import com.lino.mybatis.mapping.ResultMap;
import com.lino.mybatis.plugin.Interceptor;
import com.lino.mybatis.plugin.InterceptorChain;
import com.lino.mybatis.reflection.MetaObject;
import com.lino.mybatis.reflection.factory.DefaultObjectFactory;
import com.lino.mybatis.reflection.factory.ObjectFactory;
import com.lino.mybatis.reflection.wrapper.DefaultObjectWrapperFactory;
import com.lino.mybatis.reflection.wrapper.ObjectWrapperFactory;
import com.lino.mybatis.scripting.LanguageDriver;
import com.lino.mybatis.scripting.LanguageDriverRegistry;
import com.lino.mybatis.scripting.xmltags.XMLLanguageDriver;
import com.lino.mybatis.transaction.Transaction;
import com.lino.mybatis.transaction.jdbc.JdbcTransactionFactory;
import com.lino.mybatis.type.TypeAliasRegistry;
import com.lino.mybatis.type.TypeHandlerRegistry;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;/*** @description: 配置项*/
public class Configuration {/*** 生产执行器** @param transaction 事务* @return 执行器*/public Executor newExecutor(Transaction transaction) {Executor executor = new SimpleExecutor(this, transaction);// 配置开启缓存,创建 CachingExecutor(默认就是有缓存)装饰着模式if (cacheEnabled) {executor = new CachingExecutor(executor);}return executor;}}

在这里插入图片描述

  • 装饰器模式:是一种结构型设计模式,允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。
  • 场景介绍Mybatis 的所有 SQL 操作,都是经过 SqlSession 会话调用 SimpleExecutor 简单实现的执行器完成的,而一级缓存的操作也是在简单执行器中处理。那么这里二级缓存因为是基于二级缓存刷新操作的,所以在实现上,通过创建一个缓存执行器,包装简单执行器的处理逻辑,实现二级缓存操作。那么这里用到的就是装饰器模式,也叫俄罗斯套娃模式。
  • 同类场景:主要提前在 Cache 缓存接口的实现和 CachingExecutor 执行器中。

三、类型:行为型模式

3.1 模板模式

BaseExecutor.java

package com.lino.mybatis.executor;import com.lino.mybatis.cache.CacheKey;
import com.lino.mybatis.cache.impl.PerpetualCache;
import com.lino.mybatis.mapping.BoundSql;
import com.lino.mybatis.mapping.MappedStatement;
import com.lino.mybatis.mapping.ParameterMapping;
import com.lino.mybatis.reflection.MetaObject;
import com.lino.mybatis.session.Configuration;
import com.lino.mybatis.session.LocalCacheScope;
import com.lino.mybatis.session.ResultHandler;
import com.lino.mybatis.session.RowBounds;
import com.lino.mybatis.transaction.Transaction;
import com.lino.mybatis.type.TypeHandlerRegistry;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;/*** @description: 执行器抽象基类*/
public abstract class BaseExecutor implements Executor {@Overridepublic <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {if (closed) {throw new RuntimeException("Executor was closed.");}// 清理局部缓存,查询堆栈为0则清理。queryStack 避免递归调用清理if (queryStack == 0 && ms.isFlushCacheRequired()) {clearLocalCache();}List<E> list;try {queryStack++;// 根据cacheKey从localCache中查询数据list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;if (list == null) {list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);}} finally {queryStack--;}if (queryStack == 0) {if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {clearLocalCache();}}return list;}}

SimpleExecutor.java

package com.lino.mybatis.executor;import com.lino.mybatis.executor.statement.StatementHandler;
import com.lino.mybatis.mapping.BoundSql;
import com.lino.mybatis.mapping.MappedStatement;
import com.lino.mybatis.session.Configuration;
import com.lino.mybatis.session.ResultHandler;
import com.lino.mybatis.session.RowBounds;
import com.lino.mybatis.transaction.Transaction;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;/*** @description: 简单执行器*/
public class SimpleExecutor extends BaseExecutor {public SimpleExecutor(Configuration configuration, Transaction transaction) {super(configuration, transaction);}@Overrideprotected int doUpdate(MappedStatement ms, Object parameter) throws SQLException {Statement stmt = null;try {Configuration configuration = ms.getConfiguration();// 新建一个 StatementHandlerStatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);// 准备语句stmt = prepareStatement(handler);// StatementHandler.updatereturn handler.update(stmt);} finally {closeStatement(stmt);}}@Overrideprotected <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {Statement stmt = null;try {Configuration configuration = ms.getConfiguration();// 新建一个 StatementHandlerStatementHandler handler = configuration.newStatementHandler(this, ms, parameter, rowBounds, resultHandler, boundSql);// 准备语句stmt = prepareStatement(handler);// 返回结果return handler.query(stmt, resultHandler);} finally {closeStatement(stmt);}}private Statement prepareStatement(StatementHandler handler) throws SQLException {Statement stmt;Connection connection = transaction.getConnection();// 准备语句stmt = handler.prepare(connection);handler.parameterize(stmt);return stmt;}
}

在这里插入图片描述

  • 模板模式:是一种行为设计模式,它在超类中定义了一个算法的框架,允许子类在不修改结构的情况下重写算法的特定步骤。
  • 场景介绍:只要存在一系列可被标准定义的流程,在流程的步骤大部分是通用逻辑,只有一少部分是需要子类实现的,那么通常会采用模板模式来定义出这个标准的流程。就像 MybatisBaseExecutor 就是一个用于定义模板模式的抽象类,在这个类中把查询、修改的操作都定义出了一套标准的流程。
  • 同类场景BaseExecutorSimpleExecutorBaseTypeHandler

3.2 策略模式

TypeHandler.java

package com.lino.mybatis.type;import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;/*** @description: 类型处理器*/
public interface TypeHandler<T> {/*** 设置参数** @param ps        预处理语言* @param i         次数* @param parameter 参数对象* @param jdbcType  JDBC类型* @throws SQLException SQL异常*/void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;/*** 获取结果** @param rs         结果列表* @param columnName 列名* @return T 结果* @throws SQLException*/T getResult(ResultSet rs, String columnName) throws SQLException;/*** 获取结果** @param rs          结果列表* @param columnIndex 列的索引* @return T 结果* @throws SQLException*/T getResult(ResultSet rs, int columnIndex) throws SQLException;
}

LongTypeHandler.java

package com.lino.mybatis.type;import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;/*** @description: Long类型处理器* @author: lingjian* @createDate: 2022/11/11 13:59*/
public class LongTypeHandler extends BaseTypeHandler<Long> {@Overrideprotected void setNonNullParameter(PreparedStatement ps, int i, Long parameter, JdbcType jdbcType) throws SQLException {ps.setLong(i, parameter);}@Overrideprotected Long getNullableResult(ResultSet rs, String columnName) throws SQLException {return rs.getLong(columnName);}@Overrideprotected Long getNullableResult(ResultSet rs, int columnIndex) throws SQLException {return rs.getLong(columnIndex);}
}

在这里插入图片描述

  • 策略模式:是一种行为设计模式,它能定义一系列算法,并将每种算法分别放入独立的类中,以便算法的对象能够互相替换。
  • 场景介绍:在 Mybatis 处理 JDBC 执行后返回的结果时,需要按照不同的类型获取对应的值,这样就可以避免大量的 if 判断。所以这里基于 TypeHandler 接口对每个参数类型分别做了自己的策略实现。
  • 同类场景PooledDataSource\UnpooledDataSourceBatchExecutor\ResuseExecutor\SimpleExecutor\CachingExecutorLongTypeHandler\StringTypeHandler\DateTypeHandler

3.3 迭代器模式

PropertyTokenizer.java

package com.lino.mybatis.reflection.property;import java.util.Iterator;/*** @description: 属性分解标记*/
public class PropertyTokenizer implements Iterable<PropertyTokenizer>, Iterator<PropertyTokenizer> {// 例子:班级[0].学生.成绩/*** 属性名称:班级*/private String name;/*** 属性对象名称:班级[0]*/private String indexedName;/*** 属性索引:0*/private String index;/*** 子属性:学生*/private String children;public PropertyTokenizer(String fullName) {// 班级[0].学生.成绩:找.int delim = fullName.indexOf(".");if (delim > -1) {name = fullName.substring(0, delim);children = fullName.substring(delim + 1);} else {// 找不到.的话,取全部部分name = fullName;children = null;}indexedName = name;// 把中括号里的数字解析出来delim = name.indexOf("[");if (delim > -1) {index = name.substring(delim + 1, name.length() - 1);name = name.substring(0, delim);}}@Overridepublic Iterator<PropertyTokenizer> iterator() {return this;}@Overridepublic boolean hasNext() {return children != null;}@Overridepublic void remove() {throw new UnsupportedOperationException("Remove is not supported, as it has no meaning in the context of properties.");}@Overridepublic PropertyTokenizer next() {return new PropertyTokenizer(children);}public String getName() {return name;}public String getIndexedName() {return indexedName;}public String getIndex() {return index;}public String getChildren() {return children;}
}

在这里插入图片描述

  • 迭代器模式:是一种行为设计模式,让你能在不暴露集合底层表现形式的情况下遍历集合中所有的元素。
  • 场景介绍PropertyTokenizer 是用于 Mybatis 框架 MetaObject 反射工具包下,用于解析对象关系的迭代操作。这个类在 Mybatis 框架中使用的非常频繁,包括解析数据源配置信息并填充到数据源类上,以及参数的解析、对象的设置都会使用到这个类。
  • 同类场景PropertyTokenizer

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/121476.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

题①拷贝构造相关笔试题

问&#xff1a;此代码中有几次构造&#xff0c;几次拷贝构造&#xff1f; W f&#xff08;W u&#xff09; {W v(u);W w v;return w; } int main() {w x;w y f(x);return 0;解析&#xff1a;一次构造&#xff0c;四次拷贝构造。 再来一题 W f&#xff08;W u&#xff09;…

Redis未授权访问漏洞复现

Redis 简单使用 Redis 未设置密码&#xff0c;客户端工具可以直接链接。 Redis 是非关系型数据库系统&#xff0c;没有库表列的逻辑结构&#xff0c;仅仅以键值对的方式存储数据。 先启动容器 Redis 未设置密码&#xff0c;客户端工具可以直接链接 https://github.com/xk11z/…

Laravel 模型的关联查询 Debugbar 调试器 模型的预加载 ⑩②

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; THINK PHP &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &#x1f44…

冠达管理:券商8月调研热情高 工业机械行业受青睐

截至9月4日记者发稿&#xff0c;8月以来券商累计调研次数约1.44万次&#xff0c;环比增加超160%。其间&#xff0c;工业机械职业公司获券商调研最多。 调研逾900只个股 截至9月4日发稿&#xff0c;8月以来券商累计调研948只个股。从个股调研热度看&#xff0c;容百科技最受券…

【ES6】JavaScript中的Symbol

Symbol是JavaScript中的一种特殊的、不可变的、不可枚举的数据类型。它通常用于表示一个唯一的标识符&#xff0c;可以作为对象的属性键&#xff0c;确保对象的属性键的唯一性和不可变性。 Symbol.for()是Symbol的一个方法&#xff0c;它用于创建一个已经注册的Symbol对象。当…

基于Matlab实现多个图像融合案例(附上源码+数据集)

图像融合是将多幅图像合成为一幅图像的过程&#xff0c;旨在融合不同图像的信息以获得更多的细节和更丰富的视觉效果。在本文中&#xff0c;我们将介绍如何使用Matlab实现图像融合。 文章目录 简单案例源码数据集下载 简单案例 首先&#xff0c;我们需要了解图像融合的两种主…

理解 std::thread::join

C多线程并发编程入门&#xff08;目录&#xff09; 本文用最简单易懂的实际案例&#xff0c;讲清楚了 join 的实际内涵&#xff0c;保证你过目不忘。 Hello join 示例 join 函数是我们接触C多线程 thread 遇到的第一个函数。 比如&#xff1a; int main() {thread t(f);t.…

修改PX4飞控的imu频率

QGroundControl 连接上飞控后&#xff0c;打开 Analyze Tools 下的 MAVLink Inspector 界面 可以看到当前的 IMU 频率为50 HZ&#xff0c;或者在终端启动 mavros&#xff0c;终端输入 sudo chmod 777 /dev/ttyACM0 roslaunch mavros px4.launch 然后查看频率 rostopic hz /m…

大数据平台三大优势详解-行云管家

大数据平台三大优势详解 1、轻松进行数据共享 企业在管理以及快速发展过程中&#xff0c;有着越来越多的数据需要进行管理&#xff0c;如果单独管理则工作量巨大&#xff0c;且难免出现问题&#xff0c;同时共享难。因此需要大数据平台对数据进行统一管理&#xff0c;以及轻松…

科技驱动产业升级:浅谈制造型企业对MES系统的应用

在科技不断进步的背景下&#xff0c;制造型行业也在持续发展&#xff0c;但随之而来的挑战也不断增加。传统的管理方式已经无法满足企业的需求&#xff0c;因此许多制造型企业开始寻找新的管理模式。制造执行系统&#xff08;MES&#xff09;作为先进的制造信息技术之一&#x…

9.3.tensorRT高级(4)封装系列-自动驾驶案例项目self-driving-车道线检测

目录 前言1. 车道线检测总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习 tensorRT 高级-自动驾驶案例项目self-driving-车道…

博物学欣赏

自文艺复兴以降&#xff0c;西方开启发现世界的旅程。 这些东西对于科学、地理学、考古学、探险、旅游学、博物学、绘画学、美学无疑有着至高无上的借鉴价值。我们今天出版这些图文并茂的书籍有如斯高远的志向和目标&#xff1a; 展现自然的历史风貌 呈现万物的生态原样 复现…

第10章_索引优化与查询优化(覆盖索引, 索引下推等)

4. 子查询优化 MySQL 从 4.1 版本开始支持子查询&#xff0c;使用子查询可以进行 SELECT 语句的嵌套查询&#xff0c;即一个 SELECT 查询的结果作为另一个SELECT 语句的条件。 子查询可以一次性完成很多逻辑上需要多个步骤才能完成的 SQL 操作 。 子查询是 MySQL 的一项重…

app自动化测试(Android)

Capability 是一组键值对的集合&#xff08;比如&#xff1a;"platformName": "Android"&#xff09;。Capability 主要用于通知 Appium 服务端建立 Session 需要的信息。客户端使用特定语言生成 Capabilities&#xff0c;最终会以 JSON 对象的形式发送给 …

EDM邮件营销:使用EDM代发实现更高发送率

虽然现在进入数字时代&#xff0c;但电子邮件依然是企业跟客户之间沟通最有效的方式之一。为了吸引并且留存目标用户&#xff0c;各大企业都在努力做好EDM&#xff08;Electronic Direct Mail&#xff09;邮件营销。但是通常用电子邮箱发送外贸邮件会有发送数量和自动化的限制&…

【python爬虫】16.爬虫知识点总结复习

文章目录 前言爬虫总复习工具解析与提取&#xff08;一&#xff09;解析与提取&#xff08;二&#xff09;更厉害的请求存储更多的爬虫更强大的爬虫——框架给爬虫加上翅膀 爬虫进阶路线指引解析与提取 存储数据分析与可视化更多的爬虫更强大的爬虫——框架项目训练 反爬虫应对…

记一次Nginx代理Mysql服务的经历

背景&#xff1a; 根据组长背景描述&#xff0c;具备以下前提 1. Mysql服务器为 某A云厂商的RDS SAAS服务&#xff0c;但是不开通外网服务 2. EC2 服务器一台&#xff0c;某A云厂商LaaS服务&#xff0c;也不开通外网 3.阿里云服务器一台&#xff0c;这台服务器有服务需要连…

设计模式之策略模式

1、场景&#xff1a; 某个市场人员接到单后的报价策略(CRM系统中常见问题)。报价策略很复杂&#xff0c;可以简单作如下分类&#xff1a; • 普通客户小批量报价 • 普通客户大批量报价 • 老客户小批量报价 • 老客户大批量报价 具体选用哪个报价策略&#xff0c;这需要根据实…

全民拼购模式:美妆行业的新机遇和挑战

美妆是一个充满创意和变化的行业&#xff0c;每个人都想拥有自己独特的美丽风格。但是&#xff0c;美妆产品的价格和品质却不尽相同&#xff0c;很多消费者在购买时会遇到困惑和不满。有没有一种方法&#xff0c;可以让消费者以更低的价格买到更好的美妆产品&#xff0c;同时还…

微信小程序添加用户授权《隐私保护协议》

官方文档&#xff1a;wx.onNeedPrivacyAuthorization(function listener) | 微信开放文档 隐私协议配置 微信小程序平台上需要进行隐私配置&#xff0c;审核成功后大概半小时左右才会生效。 小程序公众平台 --- 设置 --- 服务内容声明 --- 用户隐私保护指引&#xff08;提交…