Mybatis source code analysis: the type of processor TypeHandler

Type processor TypeHandler

  TypeHandler Mybatis is a very important interface for processing parameter types, including the formal parameters and return a result set of conversion parameters. This interface defines the following methods. The method which has been implemented by a subclass BaseTypeHandler has been achieved.

  • void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
  • T getResult(ResultSet rs, String columnName) throws SQLException;
  • T getResult(ResultSet rs, int columnIndex) throws SQLException;
  • T getResult(CallableStatement cs, int columnIndex) throws SQLException;

TypeHandler inheritance and BaseTypeHandler for implementing the above method.

  We can see mybatis provides a variety of data types used for the realization of Java to Sql data type conversion. These data types include byte, short, Integer, BigDecimal, float, double, long, String, enum, Object, bool, blob, clob including date and time, and associated processing, the main types of these processors is to achieve a defined class BaseTypeHandler the method because BaseTypeHandler belong to an abstract class, on the basis implements the interface methods, and add the relevant extension methods. First, look at the source BaseTypeHandler provide implementation, in the instance of a BaseTypeHandler, he must provide Configuration configuration class, incidentally, say something here. In fact any Configuration class storage class configuration information and metadata information you want, act as the global container mybatis, such as when we write mapper file or configuration file, usually the parameter type or return type shorthand for the following code:

  <select id="list" resultType="map" useCache="true" >
        SELECT id,name,age from STUDENT
    </select>

 

  This configuration would return type to map, then mybatis show results from a query in a map form. The reason may be abbreviated when instantiating mybatis Configuration class, an alias register is initialized TypeAliasRegistry, alias register provides data types and corresponding data type referred to. Its constructor code shown below, to know why we are here only need to provide short on the line, the type of processor will use the Configuration instantiated good alias registrar, find matching data types. In addition to TypeAliasRegistry alias registrar, Configuration also provides many of the registrar, such as MapperRegistry, LanguageDriverRegistry, TypeHandlerRegistry and so on. Configuration and knowledge on the back of the registrar to continue to explain.

 1 public TypeAliasRegistry() {
 2     registerAlias("string", String.class);
 3 
 4     registerAlias("byte", Byte.class);
 5     registerAlias("long", Long.class);
 6     registerAlias("short", Short.class);
 7     registerAlias("int", Integer.class);
 8     registerAlias("integer", Integer.class);
 9     registerAlias("double", Double.class);
10     registerAlias("float", Float.class);
11     registerAlias("boolean", Boolean.class);
12 
13     registerAlias("byte[]", Byte[].class);
14     registerAlias("long[]", Long[].class);
15     registerAlias("short[]", Short[].class);
16     registerAlias("int[]", Integer[].class);
17     registerAlias("integer[]", Integer[].class);
18     registerAlias("double[]", Double[].class);
19     registerAlias("float[]", Float[].class);
20     registerAlias("boolean[]", Boolean[].class);
21 
22     registerAlias("_byte", byte.class);
23     registerAlias("_long", long.class);
24     registerAlias("_short", short.class);
25     registerAlias("_int", int.class);
26     registerAlias("_integer", int.class);
27     registerAlias("_double", double.class);
28     registerAlias("_float", float.class);
29     registerAlias("_boolean", boolean.class);
30 
31     registerAlias("_byte[]", byte[].class);
32     registerAlias("_long[]", long[].class);
33     registerAlias("_short[]", short[].class);
34     registerAlias("_int[]", int[].class);
35     registerAlias("_integer[]", int[].class);
36     registerAlias("_double[]", double[].class);
37     registerAlias("_float[]", float[].class);
38     registerAlias("_boolean[]", boolean[].class);
39 
40     registerAlias("date", Date.class);
41     registerAlias("decimal", BigDecimal.class);
42     registerAlias("bigdecimal", BigDecimal.class);
43     registerAlias("biginteger", BigInteger.class);
44     registerAlias("object", Object.class);
45 
46     registerAlias("date[]", Date[].class);
47     registerAlias("decimal[]", BigDecimal[].class);
48     registerAlias("bigdecimal[]", BigDecimal[].class);
49     registerAlias("biginteger[]", BigInteger[].class);
50     registerAlias("object[]", Object[].class);
51 
52     registerAlias("map", Map.class);
53     registerAlias("hashmap", HashMap.class);
54     registerAlias("list", List.class);
55     registerAlias("arraylist", ArrayList.class);
56     registerAlias("collection", Collection.class);
57     registerAlias("iterator", Iterator.class);
58 
59     registerAlias("ResultSet", ResultSet.class);
60   }

 

 1  public Configuration() {
 2     typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
 3     typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
 4 
 5     typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
 6     typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
 7     typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
 8 
 9     typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
10     typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
11     typeAliasRegistry.registerAlias("LRU", LruCache.class);
12     typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
13     typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
14 
15     typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
16 
17     typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
18     typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
19 
20     typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
21     typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
22     typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
23     typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
24     typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
25     typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
26     typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
27 
28     typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
29     typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
30 
31     languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
32     languageRegistry.register(RawLanguageDriver.class);
33   }

 

BaseTypeHandler

BaseTypeHandler is TypeHandler implementation class, in addition to a method to realize the interface itself, but also extends the associated method, various types of processors subsequent implements the abstract method BaseTypeHandler. First look BaseTypeHandler realize the interface method

setParameter()方法用于为PreparedStatement对象设置对应的参数类型,如果参数和JDBC类型均未设置,那么抛出TypeException,如果参数为空,那么设置参数类型为NULL,如果参数和JDBC都不为NULL,则设置指定的参数类型。在设置参数时,存在setNonNullParameter(ps, i, parameter, jdbcType);方法,该方法在BaseTypeHandler是抽象方法,假设该参数需要设置数组型参数,首先找到ArrayTypeHandler子类,观察方法中的实现.如下代码:

  Array array = rs.getArray(columnName);
    return array == null ? null : array.getArray();

 

该实现方法中实例化一个数组对象,返回一个数组,可以推论出其他的类型处理器在设置参数时,也是设置对应的参数类型的

 1  public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
 2       //如果参数和JDBC类型均未设置,那么抛出TypeException,如果参数为空,那么设置参数类型为NULL
 3     if (parameter == null) {
 4       if (jdbcType == null) {
 5         throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
 6       }
 7       try {
 8         ps.setNull(i, jdbcType.TYPE_CODE);
 9       } catch (SQLException e) {
10         throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
11                 "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " +
12                 "Cause: " + e, e);
13       }
14     } else {
15       try {
16           //设置指定的参数类型
17         setNonNullParameter(ps, i, parameter, jdbcType);
18       } catch (Exception e) {
19         throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
20                 "Try setting a different JdbcType for this parameter or a different configuration property. " +
21                 "Cause: " + e, e);
22       }
23     }
24   }

 

getResult()方法用于为设置字段对应的结果集,可以通过字段的名字和下标来设置对应的结果集,如下列代码所示,该方法也是BaseTypeHandler类的一个抽象方法,通过子类的getNullableResult()方法实现结果集的填充,仍以ArrayTypeHandler为例,查看相关的实现方法,可以看到ArrayTypeHandler只是做了对ResultSet简单的封装,想要获取什么样的数据类型就调用ResultSet中的方法。

 1 public T getResult(ResultSet rs, String columnName) throws SQLException {
 2     T result;
 3     try {
 4       result = getNullableResult(rs, columnName);
 5     } catch (Exception e) {
 6       throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set.  Cause: " + e, e);
 7     }
 8     if (rs.wasNull()) {
 9       return null;
10     } else {
11       return result;
12     }
13   }

 

 1 @Override
 2   public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
 3     Array array = rs.getArray(columnName);
 4     return array == null ? null : array.getArray();
 5   }
 6 
 7   @Override
 8   public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
 9     Array array = rs.getArray(columnIndex);
10     return array == null ? null : array.getArray();
11   }

 

JdbcType:

在介绍设置参数的时候,涉及到JdbcType类,这个类本身是枚举类,所做的事情很简单,将java.sql.Types类包装成mybatis可用的JDBC类型,代码如下所示:

 1 /**
 2  *    Copyright 2009-2015 the original author or authors.
 3  *
 4  *    Licensed under the Apache License, Version 2.0 (the "License");
 5  *    you may not use this file except in compliance with the License.
 6  *    You may obtain a copy of the License at
 7  *
 8  *       http://www.apache.org/licenses/LICENSE-2.0
 9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 package org.apache.ibatis.type;
17 
18 import java.sql.Types;
19 import java.util.HashMap;
20 import java.util.Map;
21 
22 /**
23  * @author Clinton Begin
24  */
25 public enum JdbcType {
26   /*
27    * This is added to enable basic support for the
28    * ARRAY data type - but a custom type handler is still required
29    */
30   ARRAY(Types.ARRAY),
31   BIT(Types.BIT),
32   TINYINT(Types.TINYINT),
33   SMALLINT(Types.SMALLINT),
34   INTEGER(Types.INTEGER),
35   BIGINT(Types.BIGINT),
36   FLOAT(Types.FLOAT),
37   REAL(Types.REAL),
38   DOUBLE(Types.DOUBLE),
39   NUMERIC(Types.NUMERIC),
40   DECIMAL(Types.DECIMAL),
41   CHAR(Types.CHAR),
42   VARCHAR(Types.VARCHAR),
43   LONGVARCHAR(Types.LONGVARCHAR),
44   DATE(Types.DATE),
45   TIME(Types.TIME),
46   TIMESTAMP(Types.TIMESTAMP),
47   BINARY(Types.BINARY),
48   VARBINARY(Types.VARBINARY),
49   LONGVARBINARY(Types.LONGVARBINARY),
50   NULL(Types.NULL),
51   OTHER(Types.OTHER),
52   BLOB(Types.BLOB),
53   CLOB(Types.CLOB),
54   BOOLEAN(Types.BOOLEAN),
55   CURSOR(-10), // Oracle
56   UNDEFINED(Integer.MIN_VALUE + 1000),
57   NVARCHAR(Types.NVARCHAR), // JDK6
58   NCHAR(Types.NCHAR), // JDK6
59   NCLOB(Types.NCLOB), // JDK6
60   STRUCT(Types.STRUCT),
61   JAVA_OBJECT(Types.JAVA_OBJECT),
62   DISTINCT(Types.DISTINCT),
63   REF(Types.REF),
64   DATALINK(Types.DATALINK),
65   ROWID(Types.ROWID), // JDK6
66   LONGNVARCHAR(Types.LONGNVARCHAR), // JDK6
67   SQLXML(Types.SQLXML), // JDK6
68   DATETIMEOFFSET(-155); // SQL Server 2008
69 
70   public final int TYPE_CODE;
71   private static Map<Integer,JdbcType> codeLookup = new HashMap<Integer,JdbcType>();
72 
73   static {
74     for (JdbcType type : JdbcType.values()) {
75       codeLookup.put(type.TYPE_CODE, type);
76     }
77   }
78 
79   JdbcType(int code) {
80     this.TYPE_CODE = code;
81   }
82 
83   public static JdbcType forCode(int code)  {
84     return codeLookup.get(code);
85   }
86 
87 }

 

Guess you like

Origin www.cnblogs.com/zhengzuozhanglina/p/11249657.html