国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

便宜的網(wǎng)站設(shè)計(jì)企業(yè)查詢官網(wǎng)入口

便宜的網(wǎng)站設(shè)計(jì),企業(yè)查詢官網(wǎng)入口,東臺建設(shè)網(wǎng)站,網(wǎng)站設(shè)計(jì)開發(fā)網(wǎng)站文章目錄 一、目標(biāo):參數(shù)處理器二、設(shè)計(jì):參數(shù)處理器三、實(shí)現(xiàn):參數(shù)處理器3.1 工程結(jié)構(gòu)3.2 參數(shù)處理器關(guān)系圖3.3 入?yún)?shù)校準(zhǔn)3.4 參數(shù)策略處理器3.4.1 JDBC枚舉類型修改3.4.2 類型處理器接口3.4.3 模板模式:類型處理器抽象基類3.4.4 類…

文章目錄

  • 一、目標(biāo):參數(shù)處理器
  • 二、設(shè)計(jì):參數(shù)處理器
  • 三、實(shí)現(xiàn):參數(shù)處理器
    • 3.1 工程結(jié)構(gòu)
    • 3.2 參數(shù)處理器關(guān)系圖
    • 3.3 入?yún)?shù)校準(zhǔn)
    • 3.4 參數(shù)策略處理器
      • 3.4.1 JDBC枚舉類型修改
      • 3.4.2 類型處理器接口
      • 3.4.3 模板模式:類型處理器抽象基類
      • 3.4.4 類型處理器具體的子類實(shí)現(xiàn)
      • 3.4.5 類型處理器注冊機(jī)
    • 3.5 參數(shù)構(gòu)建
      • 3.5.1 參數(shù)映射類的修改
      • 3.5.2 SQL源碼構(gòu)建器
    • 3.6 參數(shù)使用
      • 3.6.1 參數(shù)處理器接口
      • 3.6.2 默認(rèn)參數(shù)處理器
    • 3.7 參數(shù)處理器的使用
      • 3.7.1 腳本語言驅(qū)動
      • 3.7.2 XML語言驅(qū)動器
      • 3.7.3 映射器語句類修改,添加腳本語言驅(qū)動
      • 3.7.4 修改配置類
      • 3.7.5 語句處理器抽象基類
      • 3.7.6 預(yù)處理語句處理器
      • 3.7.7 默認(rèn)sqlSession實(shí)現(xiàn)類添加日志描述
  • 四、測試:參數(shù)處理器
    • 4.1 修改 DAO 接口
    • 4.2 修改 User 實(shí)體類
    • 4.3 配置Mapper文件
    • 4.4 單元測試
      • 4.4.1 提取初始化SqlSession
      • 4.4.2 基本類型參數(shù)
      • 4.4.3 對象類型參數(shù)
  • 五、總結(jié):參數(shù)處理器

一、目標(biāo):參數(shù)處理器

💡 結(jié)合參數(shù)的提取,對執(zhí)行的 SQL 進(jìn)行參數(shù)的自動化設(shè)置,而不是像我們之前那樣把參數(shù)寫成固定的。

請?zhí)砑訄D片描述

  • 在流程上,通過 DefaultSqlSession#selectOne 方法調(diào)用執(zhí)行器,并通過預(yù)處理語句處理器 PreparedStatementHandler 執(zhí)行參數(shù)設(shè)置和結(jié)果查詢。
  • 這個(gè)流程中我們處理的參數(shù)信息,也就是每個(gè) SQL 執(zhí)行時(shí),那些 ?號 需要被替換的地方,目前是通過硬編碼的方式進(jìn)行處理的。
  • 使用策略模式,處理硬編碼為自動化類型設(shè)置。

二、設(shè)計(jì):參數(shù)處理器

💡 在 SQL 拆解出參數(shù)類型之后,怎么根據(jù)不同的參數(shù)進(jìn)行不同的類型設(shè)置

  • 在自動化解析 XMLSQL 拆分出所有的參數(shù)類型后,則應(yīng)該根據(jù)不同的參數(shù)進(jìn)行不同的類型設(shè)置
    • Long 調(diào)用 ps.setLongString 調(diào)用 ps.setString
  • 這里使用 策略模式,封裝進(jìn)去類型處理器(也就是實(shí)現(xiàn) TypeHandler 接口的過程)。

在這里插入圖片描述

  • 其實(shí)關(guān)于參數(shù)的處理,因?yàn)橛泻芏嗟念愋?Long\String\Object\...),所以這里最重要的體現(xiàn)則是 策略模式 的使用。
    • 包括:構(gòu)建參數(shù)時(shí)根據(jù)類型,選擇對應(yīng)的策略類型處理器,填充到參數(shù)映射集合中。
  • 另一方面:參數(shù)的使用,也就是在執(zhí)行 DefaultSqlSession#selectOne 的鏈路中。
    • 包括:參數(shù)的設(shè)置,按照參數(shù)不同類型,獲取出對應(yīng)的處理器,以及入?yún)ⅰ?/li>
    • 注意:由于入?yún)⒅悼赡苁且粋€(gè)對象中的屬性,所以我們使用反射工具類 MetaObject 進(jìn)行值的獲取,避免由于動態(tài)的對象,沒法硬編碼獲取屬性值。

三、實(shí)現(xiàn):參數(shù)處理器

3.1 工程結(jié)構(gòu)

mybatis-step-09
|-src|-main|	|-java|		|-com.lino.mybatis|			|-binding|			|	|-MapperMethod.java|			|	|-MapperProxy.java|			|	|-MapperProxyFactory.java|			|	|-MapperRegistry.java|			|-builder|			|	|-xml|			|	|	|-XMLConfigBuilder.java|			|	|	|-XMLMapperBuilder.java|			|	|	|-XMLStatementBuilder.java|			|	|-BaseBuilder.java|			|	|-ParameterExpression.java|			|	|-SqlSourceBuilder.java|			|	|-StaticSqlSource.java|			|-datasource|			|	|-druid|			|	|	|-DruidDataSourceFacroty.java|			|	|-pooled|			|	|	|-PooledConnection.java|			|	|	|-PooledDataSource.java|			|	|	|-PooledDataSourceFacroty.java|			|	|	|-PoolState.java|			|	|-unpooled|			|	|	|-UnpooledDataSource.java|			|	|	|-UnpooledDataSourceFacroty.java|			|	|-DataSourceFactory.java|			|-executor|			|	|-parameter|			|	|	|-ParameterHandler.java|			|	|-resultset|			|	|	|-DefaultResultSetHandler.java|			|	|	|-ResultSetHandler.java|			|	|-statement|			|	|	|-BaseStatementHandler.java|			|	|	|-PreparedStatementHandler.java|			|	|	|-SimpleStatementHandler.java|			|	|	|-StatementHandler.java|			|	|-BaseExecutor.java|			|	|-Executor.java|			|	|-SimpleExecutor.java|			|-io|			|	|-Resources.java|			|-mapping|			|	|-BoundSql.java|			|	|-Environment.java|			|	|-MappedStatement.java|			|	|-ParameterMapping.java|			|	|-SqlCommandType.java|			|	|-SqlSource.java|			|-parsing|			|	|-GenericTokenParser.java|			|	|-TokenHandler.java|			|-reflection|			|	|-factory|			|	|	|-DefaultObjectFactory.java|			|	|	|-ObjectFactory.java|			|	|-invoker|			|	|	|-GetFieldInvoker.java|			|	|	|-Invoker.java|			|	|	|-MethodInvoker.java|			|	|	|-SetFieldInvoker.java|			|	|-property|			|	|	|-PropertyNamer.java|			|	|	|-PropertyTokenizer.java|			|	|-wrapper|			|	|	|-BaseWrapper.java|			|	|	|-BeanWrapper.java|			|	|	|-CollectionWrapper.java|			|	|	|-DefaultObjectWrapperFactory.java|			|	|	|-MapWrapper.java|			|	|	|-ObjectWrapper.java|			|	|	|-ObjectWrapperFactory.java|			|	|-MetaClass.java|			|	|-MetaObject.java|			|	|-Reflector.java|			|	|-SystemMetaObject.java|			|-scripting|			|	|-defaults|			|	|	|-DefaultParameterHandler.java|			|	|	|-RawSqlSource.java|			|	|-xmltags|			|	|	|-DynamicContext.java|			|	|	|-MixedSqlNode.java|			|	|	|-SqlNode.java|			|	|	|-StaticTextSqlNode.java|			|	|	|-XMLLanguageDriver.java|			|	|	|-XMLScriptBuilder.java|			|	|-LanguageDriver.java|			|	|-LanguageDriverRegistry.java|			|-session|			|	|-defaults|			|	|	|-DefaultSqlSession.java|			|	|	|-DefaultSqlSessionFactory.java|			|	|-Configuration.java|			|	|-ResultHandler.java|			|	|-SqlSession.java|			|	|-SqlSessionFactory.java|			|	|-SqlSessionFactoryBuilder.java|			|	|-TransactionIsolationLevel.java|			|-transaction|			|	|-jdbc|			|	|	|-JdbcTransaction.java|			|	|	|-JdbcTransactionFactory.java|			|	|-Transaction.java|			|	|-TransactionFactory.java|			|-type|			|	|-BaseTypeHandler.java|			|	|-IntegerTypeHandler.java|			|	|-JdbcType.java|			|	|-LongTypeHandler.java|			|	|-StringTypeHandler.java|			|	|-TypeAliasRegistry.java|			|	|-TypeHandler.java|			|	|-TypeHandlerRegistry.java|-test|-java|	|-com.lino.mybatis.test|	|-dao|	|	|-IUserDao.java|	|-po|	|	|-User.java|	|-ApiTest.java|-resources|-mapper|	|-User_Mapper.xml|-mybatis-config-datasource.xml

3.2 參數(shù)處理器關(guān)系圖

在這里插入圖片描述

  • 策略模式,核心處理主要分為三塊:類型處理、參數(shù)設(shè)置、參數(shù)使用。
    • 定義 TypeHandler 類型處理器策略接口,實(shí)現(xiàn)不同的處理策略,包括:Long、String、Integer 等。
    • 類型策略處理器實(shí)現(xiàn)完成后,需要注冊到處理器注冊機(jī)中,后續(xù)其他模塊參數(shù)的設(shè)置的使用都是從 Configuration 中獲取到 TypeHandlerRegistry 進(jìn)行使用。
    • 有了策略處理器之后,在進(jìn)行操作解析 SQL 時(shí),就可以按照不同的類型把對應(yīng)的策略處理器設(shè)置到 BoundSql#parameterMappings 參數(shù)里。

3.3 入?yún)?shù)校準(zhǔn)

💡 針對參數(shù)的傳遞?

在這里插入圖片描述

  • 這里的參數(shù)傳遞后,需要獲取第0個(gè)參數(shù),而且是硬編碼固定。
    • 這是為什么呢?這個(gè)第0個(gè)參數(shù)是哪來的,我們接口調(diào)用的方法,參數(shù)不是一個(gè)嗎?就像 User queryUserInfoById(Long id).

在這里插入圖片描述

  • 其實(shí)這個(gè)參數(shù)來自映射器代理類 MapperProxy#invoke 中,因?yàn)?invoke 反射調(diào)用的方法,入?yún)⒅惺?Object[] args,所以這個(gè)參數(shù)被傳遞到后續(xù)的參數(shù)設(shè)置中。而我們的 DAO 測試類是一個(gè)已知的固定參數(shù),所以后面硬編碼獲取了第0個(gè)參數(shù)。
    • JDK 反射調(diào)用方法操作固定方法入?yún)ⅰ?/li>
  • 現(xiàn)在我們需要根據(jù)方法的信息,給方法做簽名操作,以便于轉(zhuǎn)換入?yún)⑿畔榉椒ǖ男畔ⅰ1热?#xff1a;數(shù)組轉(zhuǎn)換為對應(yīng)的對象。

MapperMethod.java

package com.lino.mybatis.binding;import com.lino.mybatis.mapping.MappedStatement;
import com.lino.mybatis.mapping.SqlCommandType;
import com.lino.mybatis.session.Configuration;
import com.lino.mybatis.session.SqlSession;
import com.mysql.fabric.xmlrpc.base.Param;
import javassist.bytecode.SignatureAttribute;
import java.lang.reflect.Method;
import java.util.*;/*** @description: 映射器方法*/
public class MapperMethod {private final SqlCommand command;private final MethodSignature method;public MapperMethod(Class<?> mapperInterface, Method method, Configuration configuration) {this.command = new SqlCommand(configuration, mapperInterface, method);this.method = new MethodSignature(configuration, method);}public Object execute(SqlSession sqlSession, Object[] args) {Object result = null;switch (command.getType()) {case INSERT:break;case DELETE:break;case UPDATE:break;case SELECT:Object param = method.convertArgsToSqlCommandParam(args);result = sqlSession.selectOne(command.getName(), param);break;default:throw new RuntimeException("Unknown execution method for: " + command.getName());}return result;}/*** SQL 指令*/public static class SqlCommand {private final String name;private final SqlCommandType type;public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {String statementName = mapperInterface.getName() + "." + method.getName();MappedStatement ms = configuration.getMappedStatement(statementName);this.name = ms.getId();this.type = ms.getSqlCommandType();}public String getName() {return name;}public SqlCommandType getType() {return type;}}/*** 方法簽名*/public static class MethodSignature {private final SortedMap<Integer, String> params;public MethodSignature(Configuration configuration, Method method) {this.params = Collections.unmodifiableSortedMap(getParams(method));}public Object convertArgsToSqlCommandParam(Object[] args) {final int paramCount = params.size();if (args == null || paramCount == 0) {// 如果沒參數(shù)return null;} else if (paramCount == 1) {return args[params.keySet().iterator().next().intValue()];} else {// 否則,返回一個(gè)ParamMap, 修改參數(shù)名,參數(shù)名就是其位置final Map<String, Object> param = new ParamMap<>();int i = 0;for (Map.Entry<Integer, String> entry : params.entrySet()) {// 1.先加一個(gè)#{0},#{1},#{2}...參數(shù)param.put(entry.getValue(), args[entry.getKey().intValue()]);// issue #71, add param names as param1, param2...but ensure backward compatibilityfinal String genericParamName = "param" + (i + 1);if (!param.containsKey(genericParamName)) {/*2.再加一個(gè)#{param1},#{param2}...參數(shù)你可以傳遞多個(gè)參數(shù)給一個(gè)映射器方法。默認(rèn)情況下它們將會以它們在參數(shù)列表中的位置來命名,比如:#{param1},#{param2}等如果你想改變參數(shù)的名稱(只在多參數(shù)情況下),那么你可以在參數(shù)上使用@Param("paramName")注解*/param.put(genericParamName, args[entry.getKey()]);}i++;}return param;}}private SortedMap<Integer, String> getParams(Method method) {// 用一個(gè)TreeMap,這樣就保證還是按參數(shù)的先后順序final SortedMap<Integer, String> params = new TreeMap<>();final Class<?>[] argTypes = method.getParameterTypes();for (int i = 0; i < argTypes.length; i++) {String paramName = String.valueOf(params.size());// 不做 Param 的實(shí)現(xiàn),這部分不處理。params.put(i, paramName);}return params;}/*** 參數(shù)map,靜態(tài)內(nèi)部類,更嚴(yán)格的get方法,如果沒有相應(yīng)的key,報(bào)錯*/public static class ParamMap<V> extends HashMap<String, V> {private static final long serialVersionUID = -2212268410512043556L;@Overridepublic V get(Object key) {if (!super.containsKey(key)) {throw new RuntimeException("Parameter '" + key + "' not found. Available parameters are " + keySet());}return super.get(key);}}}
}
  • 在映射器方法中 MapperMethod#execute 將原來的直接將參數(shù) args 傳遞給 SqlSession#selectOne 方法,調(diào)整為轉(zhuǎn)換后再傳遞對象。
  • 這里的轉(zhuǎn)換操作就是來自于 Method#getParameterTypes 對參數(shù)的獲取和處理,于 args 進(jìn)行對比。
    • 如果是單個(gè)參數(shù),則直接返回參數(shù) Tree 樹結(jié)構(gòu)下的對應(yīng)節(jié)點(diǎn)值。
    • 非單個(gè)類型,則需要進(jìn)行循環(huán)處理,這樣轉(zhuǎn)換后的參數(shù)才能被直接使用。

3.4 參數(shù)策略處理器

  • Mybatis 的源碼包中,type 包下所提供的就是一套參數(shù)的處理策略集合。
  • 它通過定義類型處理器接口、由抽象模板實(shí)現(xiàn)并定義標(biāo)準(zhǔn)流程,定義提取抽象方法交予給子類實(shí)現(xiàn),這些之類就是各個(gè)類型處理器的具體實(shí)現(xiàn)。

3.4.1 JDBC枚舉類型修改

JdbcType.java

package com.lino.mybatis.type;import java.sql.Types;
import java.util.HashMap;
import java.util.Map;/*** @description: JDBC枚舉類型* @author: lingjian* @createDate: 2022/11/5 17:10*/
public enum JdbcType {// JDBC枚舉類型INTEGER(Types.INTEGER),FLOAT(Types.FLOAT),DOUBLE(Types.DOUBLE),DECIMAL(Types.DECIMAL),VARCHAR(Types.VARCHAR),CHAR(Types.CHAR),TIMESTAMP(Types.TIMESTAMP);public final int TYPE_CODE;private static Map<Integer, JdbcType> codeLookup = new HashMap<>();static {for (JdbcType type : JdbcType.values()) {codeLookup.put(type.TYPE_CODE, type);}}JdbcType(int code) {this.TYPE_CODE = code;}public static JdbcType forCode(int code) {return codeLookup.get(code);}
}
  • 添加 CHAR(Typcs.CHAR) 字符類型

3.4.2 類型處理器接口

TypeHandler.java

package com.lino.mybatis.type;import java.sql.PreparedStatement;
import java.sql.SQLException;/*** @description: 類型處理器*/
public interface TypeHandler<T> {/*** 設(shè)置參數(shù)** @param ps        預(yù)處理語言* @param i         次數(shù)* @param parameter 參數(shù)對象* @param jdbcType  JDBC類型* @throws SQLException SQL異常*/void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
}
  • 首先定義一個(gè)類型處理器的接口。
  • 這里設(shè)置參數(shù)也是一樣,所有不同類型的參數(shù),都可以被提取出來這些標(biāo)準(zhǔn)的參數(shù)字段和異常,后續(xù)的子類按照這個(gè)標(biāo)準(zhǔn)實(shí)現(xiàn)即可。

3.4.3 模板模式:類型處理器抽象基類

BaseTypeHandler.java

package com.lino.mybatis.type;import com.lino.mybatis.session.Configuration;
import java.sql.PreparedStatement;
import java.sql.SQLException;/*** @description: 類型處理器的基類*/
public abstract class BaseTypeHandler<T> implements TypeHandler<T> {protected Configuration configuration;public void setConfiguration(Configuration configuration) {this.configuration = configuration;}@Overridepublic void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {// 定義抽象方法,由子類實(shí)現(xiàn)不同類型的屬性設(shè)置setNonNullParameter(ps, i, parameter, jdbcType);}/*** 屬性設(shè)置:抽象方法,由子類實(shí)現(xiàn)** @param ps        預(yù)處理語言* @param i         次數(shù)* @param parameter 參數(shù)對象* @param jdbcType  JDBC類型* @throws SQLException SQL異常*/protected abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
}
  • 通過抽象基類的流程模板定義,便于一些參數(shù)的判斷和處理。

3.4.4 類型處理器具體的子類實(shí)現(xiàn)

IntegerTypeHandler.java

package com.lino.mybatis.type;import java.sql.PreparedStatement;
import java.sql.SQLException;/*** @description: Integer類型處理器*/
public class IntegerTypeHandler extends BaseTypeHandler<Integer> {@Overrideprotected void setNonNullParameter(PreparedStatement ps, int i, Integer parameter, JdbcType jdbcType) throws SQLException {ps.setInt(i, parameter);}
}

LongTypeHandler.java

package com.lino.mybatis.type;import java.sql.PreparedStatement;
import java.sql.SQLException;/*** @description: Long類型處理器*/
public class LongTypeHandler extends BaseTypeHandler<Long> {@Overrideprotected void setNonNullParameter(PreparedStatement ps, int i, Long parameter, JdbcType jdbcType) throws SQLException {ps.setLong(i, parameter);}
}

StringTypeHandler.java

package com.lino.mybatis.type;import java.sql.PreparedStatement;
import java.sql.SQLException;/*** @description: String類型處理器*/
public class StringTypeHandler extends BaseTypeHandler<String> {@Overrideprotected void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {ps.setString(i, parameter);}
}
  • 這里的接口實(shí)現(xiàn)暫時(shí)實(shí)現(xiàn)了3個(gè),分別是 IntegerTypeHandler、LongTypeHandler、StringTypeHandler。
  • Mybatis 中源碼還有30+個(gè)其他類型,可以參照源碼閱讀。

3.4.5 類型處理器注冊機(jī)

TypeHandlerRegistry.java

package com.lino.mybatis.type;import java.lang.reflect.Type;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;/*** @description: 類型處理器注冊機(jī)*/
public final class TypeHandlerRegistry {private final Map<JdbcType, TypeHandler<?>> JDBC_TYPE_HANDLER_MAP = new EnumMap<>(JdbcType.class);private final Map<Type, Map<JdbcType, TypeHandler<?>>> TYPE_HANDLER_MAP = new HashMap<>(16);private final Map<Class<?>, TypeHandler<?>> ALL_TYPE_HANDLER_MAP = new HashMap<>(16);public TypeHandlerRegistry() {register(Long.class, new LongTypeHandler());register(long.class, new LongTypeHandler());register(Integer.class, new IntegerTypeHandler());register(int.class, new IntegerTypeHandler());register(String.class, new StringTypeHandler());register(String.class, JdbcType.CHAR, new StringTypeHandler());register(String.class, JdbcType.VARCHAR, new StringTypeHandler());}private <T> void register(Type javaType, TypeHandler<? extends T> typeHandler) {register(javaType, null, typeHandler);}private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {if (null != javaType) {Map<JdbcType, TypeHandler<?>> map = TYPE_HANDLER_MAP.computeIfAbsent(javaType, k -> new HashMap<>(16));map.put(jdbcType, handler);}ALL_TYPE_HANDLER_MAP.put(handler.getClass(), handler);}@SuppressWarnings("unchecked")public TypeHandler<?> getTypeHandler(Class<?> type, JdbcType jdbcType) {return getTypeHandler((Type) type, jdbcType);}public boolean hasTypeHandler(Class<?> javaType) {return hasTypeHandler(javaType, null);}public boolean hasTypeHandler(Class<?> javaType, JdbcType jdbcType) {return javaType != null && getTypeHandler((Type) javaType, jdbcType) != null;}private <T> TypeHandler<T> getTypeHandler(Type type, JdbcType jdbcType) {Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = TYPE_HANDLER_MAP.get(type);TypeHandler<?> handler = null;if (jdbcHandlerMap != null) {handler = jdbcHandlerMap.get(jdbcType);if (handler == null) {handler = jdbcHandlerMap.get(null);}}// type driver generics herereturn (TypeHandler<T>) handler;}
}
  • 這里在構(gòu)造函數(shù)中,新增加了 LongTypeHandler、IntegerTypeHandler、StringTypeHandler 三種類型的注冊機(jī)。
  • 同時(shí)注意到,無論是對象類型,還是基本類型,都是一個(gè)類型處理器。只不過在注冊的時(shí)候多注冊了一個(gè)。
    • 這種操作方式和我們平常的業(yè)務(wù)開發(fā)中,也是一樣的。一種是多注冊,另外一種是判斷處理。

3.5 參數(shù)構(gòu)建

  • 需要對 SqlSourceBuilder 源碼構(gòu)建器中,創(chuàng)建參數(shù)映射 ParameterMapping 需要添加參數(shù)處理器的內(nèi)容。
    • 因?yàn)橹挥羞@樣才能方便的從參數(shù)映射中獲取到對應(yīng)類型的處理器進(jìn)行使用。
  • 需要完善 ParameterMappping 添加 TypeHandler 屬性信息。
    • 以及在 ParameterMappingTokenHandler#buildParameterMapping 處理參數(shù)映射時(shí),構(gòu)建出參數(shù)的映射。

3.5.1 參數(shù)映射類的修改

ParameterMapping.java

package com.lino.mybatis.mapping;import com.lino.mybatis.session.Configuration;
import com.lino.mybatis.type.JdbcType;
import com.lino.mybatis.type.TypeHandler;
import com.lino.mybatis.type.TypeHandlerRegistry;/*** @description: 參數(shù)映射 #{property,javaType=int,jdbcType=NUMERIC}*/
public class ParameterMapping {private Configuration configuration;/*** property*/private String property;/*** javaType = int*/private Class<?> javaType = Object.class;/*** javaType = NUMERIC*/private JdbcType jdbcType;/*** 類型處理器*/private TypeHandler<?> typeHandler;private ParameterMapping() {}public static class Builder {private ParameterMapping parameterMapping = new ParameterMapping();public Builder(Configuration configuration, String property, Class<?> javaType) {parameterMapping.configuration = configuration;parameterMapping.property = property;parameterMapping.javaType = javaType;}public Builder javaType(Class<?> javaType) {parameterMapping.javaType = javaType;return this;}public Builder jdbcType(JdbcType jdbcType) {parameterMapping.jdbcType = jdbcType;return this;}public ParameterMapping build() {if (parameterMapping.typeHandler == null && parameterMapping.javaType != null) {Configuration configuration = parameterMapping.configuration;TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();parameterMapping.typeHandler = typeHandlerRegistry.getTypeHandler(parameterMapping.javaType, parameterMapping.jdbcType);}return parameterMapping;}}public Configuration getConfiguration() {return configuration;}public String getProperty() {return property;}public Class<?> getJavaType() {return javaType;}public JdbcType getJdbcType() {return jdbcType;}public TypeHandler<?> getTypeHandler() {return typeHandler;}
}
  • build 添加類型處理器的處理判斷

3.5.2 SQL源碼構(gòu)建器

SqlSourceBuilder.java

package com.lino.mybatis.builder;import com.lino.mybatis.mapping.ParameterMapping;
import com.lino.mybatis.mapping.SqlSource;
import com.lino.mybatis.parsing.GenericTokenParser;
import com.lino.mybatis.parsing.TokenHandler;
import com.lino.mybatis.reflection.MetaClass;
import com.lino.mybatis.reflection.MetaObject;
import com.lino.mybatis.session.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;/*** @description: SQL源碼構(gòu)建器*/
public class SqlSourceBuilder extends BaseBuilder {private static Logger logger = LoggerFactory.getLogger(SqlSourceBuilder.class);private static final String parameterProperties = "javaType,jdbcType,mode,numericScale,resultMap,typeHandler,jdbcTypeName";public SqlSourceBuilder(Configuration configuration) {super(configuration);}public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);String sql = parser.parse(originalSql);// 返回靜態(tài)SQLreturn new StaticSqlSource(configuration, sql, handler.getParameterMappings());}private static class ParameterMappingTokenHandler extends BaseBuilder implements TokenHandler {private List<ParameterMapping> parameterMappings = new ArrayList<>();private Class<?> parameterType;private MetaObject metaParameters;public ParameterMappingTokenHandler(Configuration configuration, Class<?> parameterType, Map<String, Object> additionalParameters) {super(configuration);this.parameterType = parameterType;this.metaParameters = configuration.newMetaObject(additionalParameters);}public List<ParameterMapping> getParameterMappings() {return parameterMappings;}@Overridepublic String handleToken(String content) {parameterMappings.add(buildParameterMapping(content));return "?";}/*** 構(gòu)建參數(shù)映射** @param content 參數(shù)* @return 參數(shù)映射*/private ParameterMapping buildParameterMapping(String content) {// 先解析參數(shù)映射,就是轉(zhuǎn)化成一個(gè) HashMap | #{favouriteSection,jdbcType=VARCHAR}Map<String, String> propertiesMap = new ParameterExpression(content);String property = propertiesMap.get("property");Class<?> propertyType;if (typeHandlerRegistry.hasTypeHandler(parameterType)) {propertyType = parameterType;} else if (property != null) {MetaClass metaClass = MetaClass.forClass(parameterType);if (metaClass.hasGetter(property)) {propertyType = metaClass.getGetterType(property);} else {propertyType = Object.class;}} else {propertyType = Object.class;}logger.info("構(gòu)建參數(shù)映射 property:{} propertyType:{}", property, propertyType);ParameterMapping.Builder builder = new ParameterMapping.Builder(configuration, property, propertyType);return builder.build();}}
}
  • 這部分就是對參數(shù)的細(xì)化處理,構(gòu)建出參數(shù)的映射關(guān)系。
    • 首先是 if 判斷對應(yīng)的參數(shù)類型是否在 TypeHandlerRegistry 注冊器中。
    • 如果不在則拆解對象,按屬性進(jìn)行獲取 propertyType 的操作。
  • 這一塊也用到了 MetaClass 反射工具類的使用。

3.6 參數(shù)使用

  • 參數(shù)構(gòu)建完成后,就可以在 DefaultSqlSession#selectOne 調(diào)用時(shí)設(shè)置參數(shù)使用了。
    • 鏈路:Executor#query -> SimpleExecutor#doQuery -> StatementHandler#parameterize -> PreparedStatementHandler#parameterize -> ParameterHandler#setParameters。
    • ParameterHandler#setParameters 就可以看到了根據(jù)參數(shù)的不同處理器循環(huán)設(shè)置參數(shù)。

3.6.1 參數(shù)處理器接口

ParameterHandler.java

package com.lino.mybatis.executor.parameter;import java.sql.PreparedStatement;
import java.sql.SQLException;/*** @description: 參數(shù)處理器*/
public interface ParameterHandler {/*** 獲取參數(shù)** @return 參數(shù)*/Object getParameterObject();/*** 設(shè)置參數(shù)** @param ps 預(yù)處理語句對象* @throws SQLException sql異常*/void setParameters(PreparedStatement ps) throws SQLException;
}

3.6.2 默認(rèn)參數(shù)處理器

DefaultParameterHandler.java

package com.lino.mybatis.scripting.defaults;import com.alibaba.fastjson.JSON;
import com.lino.mybatis.executor.parameter.ParameterHandler;
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.type.JdbcType;
import com.lino.mybatis.type.TypeHandler;
import com.lino.mybatis.type.TypeHandlerRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;/*** @description: 默認(rèn)參數(shù)處理器*/
public class DefaultParameterHandler implements ParameterHandler {private Logger logger = LoggerFactory.getLogger(DefaultParameterHandler.class);private final TypeHandlerRegistry typeHandlerRegistry;private final MappedStatement mappedStatement;private final Object parameterObject;private BoundSql boundSql;private 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;}@Overridepublic Object getParameterObject() {return parameterObject;}@Overridepublic void setParameters(PreparedStatement ps) throws SQLException {List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();if (null != parameterMappings) {for (int i = 0; i < parameterMappings.size(); i++) {ParameterMapping parameterMapping = parameterMappings.get(i);String propertyName = parameterMapping.getProperty();Object value;if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {value = parameterObject;} else {// 通過 MetaObject.getValue 反射取得值設(shè)置進(jìn)去MetaObject metaObject = configuration.newMetaObject(parameterObject);value = metaObject.getValue(propertyName);}JdbcType jdbcType = parameterMapping.getJdbcType();// 設(shè)置參數(shù)logger.info("根據(jù)每個(gè)ParameterMapping中的TypeHandler設(shè)置對應(yīng)的參數(shù)信息 value:{}", JSON.toJSONString(value));TypeHandler typeHandler = parameterMapping.getTypeHandler();typeHandler.setParameter(ps, i + 1, value, jdbcType);}}}
}
  • 每一個(gè)循環(huán)的參數(shù)設(shè)置,都是從 BoundSql 中獲取 ParameterMapping 集合進(jìn)行循環(huán)操作,而這個(gè)集合參數(shù)就是我們前面 ParameterMappingTokenHandler#buildParameterMapping 構(gòu)建參數(shù)映射時(shí)處理的。
  • 設(shè)置參數(shù)時(shí)根據(jù)參數(shù)的 parameterObject 入?yún)⑿畔?#xff0c;判斷是否基本類型,如果不是則從對象中進(jìn)行拆解獲取(也就是一個(gè)對象A中包括對象B),處理完成后就可以準(zhǔn)確拿到對應(yīng)的入?yún)⒅怠?
    • 入?yún)⒅翟?MapperMethod 中已經(jīng)處理了一遍 方法簽名。
  • 基本信息獲取完成后,則根據(jù)參數(shù)類型獲取到對應(yīng)的 TypeHandler 類型處理器,也就是找到 IntegerTypeHandler、LongTypeHandler、StringTypeHandler 等,確定找到以后,則可以進(jìn)行對應(yīng)的參數(shù)設(shè)置。
    • typeHandler.setParameter(ps, i + 1, value, jdbcType) 通過這樣的方式把我們之前硬編碼的操作進(jìn)行解耦。

3.7 參數(shù)處理器的使用

3.7.1 腳本語言驅(qū)動

LanguageDriver.java

package com.lino.mybatis.scripting;import com.lino.mybatis.executor.parameter.ParameterHandler;
import com.lino.mybatis.mapping.BoundSql;
import com.lino.mybatis.mapping.MappedStatement;
import com.lino.mybatis.mapping.SqlSource;
import com.lino.mybatis.session.Configuration;
import org.dom4j.Element;/*** @description: 腳本語言驅(qū)動*/
public interface LanguageDriver {/*** 創(chuàng)建SQL源** @param configuration 配置項(xiàng)* @param script        元素* @param parameterType 參數(shù)類型* @return SqlSource SQL源碼*/SqlSource createSqlSource(Configuration configuration, Element script, Class<?> parameterType);/*** 創(chuàng)建參數(shù)處理器** @param mappedStatement 映射器語句類* @param parameterObject 參數(shù)對象* @param boundSql        sql語句* @return ParameterHandler 參數(shù)處理器*/ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql);
}
  • 添加創(chuàng)建參數(shù)處理器接口

3.7.2 XML語言驅(qū)動器

XMLLanguageDriver.java

package com.lino.mybatis.scripting.xmltags;import com.lino.mybatis.executor.parameter.ParameterHandler;
import com.lino.mybatis.mapping.BoundSql;
import com.lino.mybatis.mapping.MappedStatement;
import com.lino.mybatis.mapping.SqlSource;
import com.lino.mybatis.scripting.LanguageDriver;
import com.lino.mybatis.scripting.defaults.DefaultParameterHandler;
import com.lino.mybatis.session.Configuration;
import org.dom4j.Element;/*** @description: XML 語言驅(qū)動器*/
public class XMLLanguageDriver implements LanguageDriver {@Overridepublic SqlSource createSqlSource(Configuration configuration, Element script, Class<?> parameterType) {// 用XML腳本構(gòu)建器解析XMLScriptBuilder builder = new XMLScriptBuilder(configuration, script, parameterType);return builder.parseScriptNode();}@Overridepublic ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);}
}

3.7.3 映射器語句類修改,添加腳本語言驅(qū)動

MappedStatement.java

package com.lino.mybatis.mapping;import com.lino.mybatis.scripting.LanguageDriver;
import com.lino.mybatis.session.Configuration;/*** @description: 映射器語句類*/
public class MappedStatement {private Configuration configuration;private String id;private SqlCommandType sqlCommandType;private SqlSource sqlSource;Class<?> resultType;private LanguageDriver lang;public MappedStatement() {}public static class Builder {private MappedStatement mappedStatement = new MappedStatement();public Builder(Configuration configuration, String id, SqlCommandType sqlCommandType, SqlSource sqlSource, Class<?> resultType) {mappedStatement.configuration = configuration;mappedStatement.id = id;mappedStatement.sqlCommandType = sqlCommandType;mappedStatement.sqlSource = sqlSource;mappedStatement.resultType = resultType;mappedStatement.lang = configuration.getDefaultScriptingLanguageInstance();}public MappedStatement build() {assert mappedStatement.configuration != null;assert mappedStatement.id != null;return mappedStatement;}}public Configuration getConfiguration() {return configuration;}public String getId() {return id;}public SqlCommandType getSqlCommandType() {return sqlCommandType;}public SqlSource getSqlSource() {return sqlSource;}public Class<?> getResultType() {return resultType;}public LanguageDriver getLang() {return lang;}
}

3.7.4 修改配置類

Configuration.java

package com.lino.mybatis.session;import com.lino.mybatis.binding.MapperRegistry;
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.Executor;
import com.lino.mybatis.executor.SimpleExecutor;
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.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: 配置項(xiàng)*/
public class Configuration {/*** 環(huán)境*/protected Environment environment;/*** 映射注冊機(jī)*/protected MapperRegistry mapperRegistry = new MapperRegistry(this);/*** 映射的語句,存在Map里*/protected final Map<String, MappedStatement> mappedStatements = new HashMap<>(16);/*** 類型別名注冊機(jī)*/protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();/*** 腳本語言注冊器*/protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();/*** 類型處理器注冊機(jī)*/protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();/*** 對象工廠*/protected ObjectFactory objectFactory = new DefaultObjectFactory();/*** 對象包裝工廠*/protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();/*** 準(zhǔn)備資源列表*/protected final Set<String> loadedResources = new HashSet<>();/*** 數(shù)據(jù)庫ID*/protected String databaseId;public Configuration() {typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);typeAliasRegistry.registerAlias("DRUID", DruidDataSourceFactory.class);typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);}public void addMappers(String packageName) {mapperRegistry.addMappers(packageName);}public <T> void addMapper(Class<T> type) {mapperRegistry.addMapper(type);}public <T> T getMapper(Class<T> type, SqlSession sqlSession) {return mapperRegistry.getMapper(type, sqlSession);}public boolean hasMapper(Class<?> type) {return mapperRegistry.hasMapper(type);}public void addMappedStatement(MappedStatement ms) {mappedStatements.put(ms.getId(), ms);}public MappedStatement getMappedStatement(String id) {return mappedStatements.get(id);}public TypeAliasRegistry getTypeAliasRegistry() {return typeAliasRegistry;}public Environment getEnvironment() {return environment;}public void setEnvironment(Environment environment) {this.environment = environment;}public String getDatabaseId() {return databaseId;}/*** 生產(chǎn)執(zhí)行器** @param transaction 事務(wù)* @return 執(zhí)行器*/public Executor newExecutor(Transaction transaction) {return new SimpleExecutor(this, transaction);}/*** 創(chuàng)建語句處理器** @param executor        執(zhí)行器* @param mappedStatement 映射器語句類* @param parameter       參數(shù)* @param resultHandler   結(jié)果處理器* @param boundSql        SQL語句* @return StatementHandler 語句處理器*/public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, ResultHandler resultHandler, BoundSql boundSql) {return new PreparedStatementHandler(executor, mappedStatement, parameter, resultHandler, boundSql);}/*** 創(chuàng)建結(jié)果集處理器** @param executor        執(zhí)行器* @param mappedStatement 映射器語句類* @param boundSql        SQL語句* @return ResultSetHandler 結(jié)果集處理器*/public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, BoundSql boundSql) {return new DefaultResultSetHandler(executor, mappedStatement, boundSql);}/*** 創(chuàng)建元對象** @param object 原對象* @return 元對象*/public MetaObject newMetaObject(Object object) {return MetaObject.forObject(object, objectFactory, objectWrapperFactory);}/*** 創(chuàng)建類型處理器注冊機(jī)** @return TypeHandlerRegistry 類型處理器注冊機(jī)*/public TypeHandlerRegistry getTypeHandlerRegistry() {return typeHandlerRegistry;}/*** 是否包含資源** @param resource 資源* @return 是否*/public boolean isResourceLoaded(String resource) {return loadedResources.contains(resource);}/*** 添加資源** @param resource 資源*/public void addLoadedResource(String resource) {loadedResources.add(resource);}/*** 獲取腳本語言注冊機(jī)** @return languageRegistry 腳本語言注冊機(jī)*/public LanguageDriverRegistry getLanguageRegistry() {return languageRegistry;}/*** 獲取參數(shù)處理器** @param mappedStatement 映射器語言類型* @param parameterObject 參數(shù)對象* @param boundSql        SQL語句* @return ParameterHandler參數(shù)處理器*/public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {// 創(chuàng)建參數(shù)處理器ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);return parameterHandler;}/*** 獲取默認(rèn)腳本語言驅(qū)動** @return 腳本語言驅(qū)動*/public LanguageDriver getDefaultScriptingLanguageInstance() {return languageRegistry.getDefaultDriver();}
}
  • 添加獲取默認(rèn)腳本語言驅(qū)動 getDefaultScriptingLanguageInstance
  • 添加獲取參數(shù)處理器 newParameterHandler

3.7.5 語句處理器抽象基類

BaseStatementHandler.java

package com.lino.mybatis.executor.statement;import com.lino.mybatis.executor.Executor;
import com.lino.mybatis.executor.parameter.ParameterHandler;
import com.lino.mybatis.executor.resultset.ResultSetHandler;
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 java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;/*** @description: 語句處理器抽象基類*/
public abstract class BaseStatementHandler implements StatementHandler {protected final Configuration configuration;protected final Executor executor;protected final MappedStatement mappedStatement;protected final Object parameterObject;protected final ResultSetHandler resultSetHandler;protected final ParameterHandler parameterHandler;protected BoundSql boundSql;public BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, ResultHandler resultHandler, BoundSql boundSql) {this.configuration = mappedStatement.getConfiguration();this.executor = executor;this.mappedStatement = mappedStatement;this.parameterObject = parameterObject;this.boundSql = boundSql;this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, boundSql);}@Overridepublic Statement prepare(Connection connection) {Statement statement = null;try {// 實(shí)例化 Statementstatement = instantiateStatement(connection);// 參數(shù)設(shè)置,可以被抽取,提供配置statement.setQueryTimeout(350);statement.setFetchSize(10000);return statement;} catch (Exception e) {throw new RuntimeException("Error prepare statement. Cause: " + e, e);}}protected abstract Statement instantiateStatement(Connection connection) throws SQLException;}
  • 添加 ParameterHandler 參數(shù)處理器

3.7.6 預(yù)處理語句處理器

PreparedStatementHandler.java

package com.lino.mybatis.executor.statement;import com.lino.mybatis.executor.Executor;
import com.lino.mybatis.mapping.BoundSql;
import com.lino.mybatis.mapping.MappedStatement;
import com.lino.mybatis.session.ResultHandler;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;/*** @description: 預(yù)處理語句處理器(PREPARED)*/
public class PreparedStatementHandler extends BaseStatementHandler {public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, ResultHandler resultSetHandler, BoundSql boundSql) {super(executor, mappedStatement, parameterObject, resultSetHandler, boundSql);}@Overrideprotected Statement instantiateStatement(Connection connection) throws SQLException {String sql = boundSql.getSql();return connection.prepareStatement(sql);}@Overridepublic void parameterize(Statement statement) throws SQLException {parameterHandler.setParameters((PreparedStatement) statement);}@Overridepublic <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {PreparedStatement ps = (PreparedStatement) statement;ps.execute();return resultSetHandler.handleResultSets(ps);}
}

3.7.7 默認(rèn)sqlSession實(shí)現(xiàn)類添加日志描述

DefaultSqlSession.java

package com.lino.mybatis.session.defaults;import com.alibaba.fastjson.JSON;
import com.lino.mybatis.executor.Executor;
import com.lino.mybatis.mapping.MappedStatement;
import com.lino.mybatis.session.Configuration;
import com.lino.mybatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;/*** @description: 默認(rèn)sqlSession實(shí)現(xiàn)類*/
public class DefaultSqlSession implements SqlSession {private Logger logger = LoggerFactory.getLogger(DefaultSqlSession.class);...@Overridepublic <T> T selectOne(String statement, Object parameter) {logger.info("執(zhí)行查詢 statement:{} parameter:{}", statement, JSON.toJSONString(parameter));MappedStatement ms = configuration.getMappedStatement(statement);List<T> list = executor.query(ms, parameter, Executor.NO_RESULT_HANDLER, ms.getSqlSource().getBoundSql(parameter));return list.get(0);}...
}

四、測試:參數(shù)處理器

4.1 修改 DAO 接口

IUserDao.java

package com.lino.mybatis.test.dao;import com.lino.mybatis.test.po.User;/*** @Description: 用戶持久層*/
public interface IUserDao {/*** 根據(jù)ID查詢用戶信息** @param uId ID* @return User 用戶*/User queryUserInfoById(Long uId);/*** 根據(jù)用戶對象查詢用戶信息* @param user 用戶* @return User 用戶*/User queryUserInfo(User user);
}

4.2 修改 User 實(shí)體類

User.java

package com.lino.mybatis.test.po;import java.util.Date;/*** @description: 用戶實(shí)例類*/
public class User {private Long id;/*** 用戶ID*/private String userId;/*** 頭像*/private String userHead;/*** 用戶名稱*/private String userName;/*** 創(chuàng)建時(shí)間*/private Date createTime;/*** 更新時(shí)間*/private Date updateTime;public User() {}public User(Long id, String userId) {this.id = id;this.userId = userId;}// getter/setter
}

4.3 配置Mapper文件

User_Mapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lino.mybatis.test.dao.IUserDao"><select id="queryUserInfoById" parameterType="java.lang.Long" resultType="com.lino.mybatis.test.po.User">SELECT id, userId, userName, userHeadFROM userWHERE id = #{id}</select><select id="queryUserInfo" parameterType="com.lino.mybatis.test.po.User" resultType="com.lino.mybatis.test.po.User">SELECT id, userId, userName, userHeadFROM userwhere id = #{id} and userId = #{userId}</select>
</mapper>

4.4 單元測試

4.4.1 提取初始化SqlSession

ApiTest.java

private SqlSession sqlSession;@Before
public void init() throws IOException {// 1.從SqlSessionFactory中獲取SqlSessionSqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config-datasource.xml"));sqlSession = sqlSessionFactory.openSession();
}
  • 因?yàn)榻酉聛硇枰?yàn)證兩種不同入?yún)⒌膯卧獪y試,所以提取 從SqlSessionFactory中獲取SqlSession

4.4.2 基本類型參數(shù)

ApiTest.java

@Test
public void test_queryUserInfoId() {// 1.獲取映射器對象IUserDao userDao = sqlSession.getMapper(IUserDao.class);// 2.測試驗(yàn)證: 基本參數(shù)User user = userDao.queryUserInfoById(1L);logger.info("測試結(jié)果:{}", JSON.toJSONString(user));
}

測試結(jié)果

10:06:48.775 [main] INFO  c.l.mybatis.builder.SqlSourceBuilder - 構(gòu)建參數(shù)映射 property:id propertyType:class java.lang.Long
10:06:48.934 [main] INFO  c.l.m.s.defaults.DefaultSqlSession - 執(zhí)行查詢 statement:com.lino.mybatis.test.dao.IUserDao.queryUserInfoById parameter:1
10:06:49.805 [main] INFO  c.l.m.d.pooled.PooledDataSource - Created connention 1043208434.
10:06:49.815 [main] INFO  c.l.m.s.d.DefaultParameterHandler - 根據(jù)每個(gè)ParameterMapping中的TypeHandler設(shè)置對應(yīng)的參數(shù)信息 value:1
10:06:49.838 [main] INFO  com.lino.mybatis.test.ApiTest - 測試結(jié)果:{"id":1,"userHead":"1_04","userId":"10001","userName":"小靈哥"}

在這里插入圖片描述

  • 從測試過程中可以在 DefaultParameterHandler#setParameters 中打斷點(diǎn),驗(yàn)證方法參數(shù)以及獲得到的類型處理器。
  • 這里測試可以通過,可以滿足基本類型對象的入?yún)⑿畔ⅰ?/li>

4.4.3 對象類型參數(shù)

ApiTest.java

@Test
public void test_queryUserInfo() {// 1.獲取映射器對象IUserDao userDao = sqlSession.getMapper(IUserDao.class);// 2.測試驗(yàn)證: 對象參數(shù)User user = userDao.queryUserInfo(new User(1L, "10001"));logger.info("測試結(jié)果:{}", JSON.toJSONString(user));
}

測試結(jié)果

10:10:05.878 [main] INFO  c.l.mybatis.builder.SqlSourceBuilder - 構(gòu)建參數(shù)映射 property:id propertyType:class java.lang.Long
10:10:05.878 [main] INFO  c.l.mybatis.builder.SqlSourceBuilder - 構(gòu)建參數(shù)映射 property:userId propertyType:class java.lang.String
10:10:05.947 [main] INFO  c.l.m.s.defaults.DefaultSqlSession - 執(zhí)行查詢 statement:com.lino.mybatis.test.dao.IUserDao.queryUserInfo parameter:{"id":1,"userId":"10001"}
10:10:06.574 [main] INFO  c.l.m.d.pooled.PooledDataSource - Created connention 1107024580.
10:10:06.590 [main] INFO  c.l.m.s.d.DefaultParameterHandler - 根據(jù)每個(gè)ParameterMapping中的TypeHandler設(shè)置對應(yīng)的參數(shù)信息 value:1
10:10:06.590 [main] INFO  c.l.m.s.d.DefaultParameterHandler - 根據(jù)每個(gè)ParameterMapping中的TypeHandler設(shè)置對應(yīng)的參數(shù)信息 value:"10001"
10:10:06.590 [main] INFO  com.lino.mybatis.test.ApiTest - 測試結(jié)果:{"id":1,"userHead":"1_04","userId":"10001","userName":"小靈哥"}

在這里插入圖片描述

  • 從測試結(jié)果驗(yàn)證對象參數(shù) User 中包含兩個(gè)屬性時(shí),檢查我們的代碼處理過程,驗(yàn)證是否可以正確獲取到兩個(gè)類型處理器,分別設(shè)置參數(shù)的過程。
  • 從測試結(jié)果看,可以看到測試通過,并打印了相關(guān)參數(shù)的構(gòu)建和使用。

五、總結(jié):參數(shù)處理器

  • 已經(jīng)把一個(gè) ORM 框架的基本流程串聯(lián)起來了,包含的分包結(jié)構(gòu):構(gòu)建、綁定、映射、反射、執(zhí)行、類型、事務(wù)、數(shù)據(jù)源等。
  • 參數(shù)類型的策略化設(shè)計(jì),通過策略解耦,模板定義流程,讓我們整個(gè)參數(shù)設(shè)置變得更加清晰。
  • 還有一些細(xì)節(jié)的功能點(diǎn):MapperMethod 中添加方法簽名、類型處理器創(chuàng)建和使用時(shí),都使用了 MetaObject 反射器工具類進(jìn)行處理。
http://aloenet.com.cn/news/47779.html

相關(guān)文章:

  • 遂寧網(wǎng)站開發(fā)廣告軟文小故事800字
  • 做社交網(wǎng)站有哪些全世界足球排名前十位
  • 小程序平臺商城seo搜索引擎優(yōu)化實(shí)戰(zhàn)
  • 建設(shè)企業(yè)網(wǎng)站目的查看域名每日ip訪問量
  • 中工信融營銷型網(wǎng)站建設(shè)百度精準(zhǔn)獲客平臺
  • 做外貿(mào)翻譯用哪個(gè)網(wǎng)站好百度app安裝免費(fèi)下載
  • 南昌淘寶網(wǎng)站制作公司百度競價(jià)排名廣告定價(jià)
  • 建設(shè)網(wǎng)站目的是什么成人用品哪里進(jìn)貨好
  • 正規(guī)的網(wǎng)站建設(shè)企業(yè)網(wǎng)站制作seo手機(jī)搜索快速排名
  • 青島 google seo杭州網(wǎng)站優(yōu)化平臺
  • 時(shí)尚網(wǎng)站首頁設(shè)計(jì)中國國家人事人才培訓(xùn)網(wǎng)證書查詢
  • 做校園二手交易網(wǎng)站的目的疫情最新消息
  • 網(wǎng)站建設(shè) ur建站鹽城seo網(wǎng)站優(yōu)化軟件
  • web優(yōu)秀網(wǎng)站h5案例分享今日最新國際新聞
  • 淮北哪有做淘寶網(wǎng)站網(wǎng)盤資源大全
  • 網(wǎng)站建設(shè)公司專業(yè)高質(zhì)量外鏈
  • 企業(yè)服務(wù)平臺網(wǎng)站建設(shè)數(shù)據(jù)交換平臺
  • 織夢修改網(wǎng)站背景顏色湛江今日頭條
  • 商丘做網(wǎng)站哪家好如何刷關(guān)鍵詞指數(shù)
  • 邵陽競價(jià)網(wǎng)站建設(shè)設(shè)計(jì)怎么創(chuàng)建域名
  • 深圳哪家建設(shè)網(wǎng)站公司好國內(nèi)最大的搜索引擎
  • 做玩具訂制網(wǎng)站好處站長之家seo綜合查詢
  • 有沒有專門做外貿(mào)的網(wǎng)站互聯(lián)網(wǎng)廣告管理暫行辦法
  • 泉州做網(wǎng)站的公司濰坊網(wǎng)站關(guān)鍵詞推廣
  • 網(wǎng)站開發(fā)網(wǎng)站設(shè)計(jì)人力資源培訓(xùn)
  • 青海網(wǎng)站設(shè)計(jì)高端凌哥seo技術(shù)博客
  • 天津網(wǎng)站建設(shè)公騰訊廣告推廣平臺
  • 重慶網(wǎng)站建設(shè)招標(biāo)全球十大搜索引擎排名
  • 日常網(wǎng)站維護(hù)得物app的網(wǎng)絡(luò)營銷分析論文
  • 揚(yáng)州網(wǎng)站制作媒體營銷平臺