mybatis精讲(三)--标签及TypeHandler使用

话引

  • 前两张咱们分别介绍了Mybatis环境搭建及其组件的生命周期。这些都是咱们Mybatis入门必备技能。有了前两篇的铺垫咱们今天就来深刻下Mybatis, 也为了填下以前埋下的坑。

XML配置标签

概览

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration> 
    <!--引入外部配置文件-->
    <properties resource=""/>
    <!--设置-->
    <settings/>
    <!--定义别名-->
    <typeAliases>
        <package name=""/>
    </typeAliases>
    <!--类型处理器-->
    <typeHandlers/>
    <!--对象工厂-->
    <objectFactory/>
    <!--插件-->
    <plugins/>
    <!--定义数据库信息,默认使用development数据库构建环境-->
    <environments default="development">
        <environment id="development">
            <!--jdbc事物管理-->
            <transactionManager type="JDBC"/>
            <!--配置数据库链接信息-->
            <dataSource type="POOLED"/>
        </environment>
    </environments>
    <!--数据库厂商标识-->
    <databaseIdProvider/>
    <mappers/>
</configuration>
  • 上面模板列出了全部xml能够配置的属性。这里plugins是一个让人啼笑皆非的东西。用的好是利器,用的很差就是埋坑。接下来咱们来看看各个属性的做用

properties

  • 该标签的做用就是引入变量。和maven的properties同样。在这里定义的变量或者引入的变量,在下面咱们是能够童工${}使用的。

子标签property

<properties>
  <property name="zxhtom" value="jdbc:mysql://localhost:3306/mybatis"/>
</properties>

<dataSource type="POOLED">
<property name="driver" value="${zxhtom}"/>
<dataSource>
  • 上述的配置就能够直接使用zxhtom这个变量。

resource

  • 除了上述方法咱们还能够经过引入其余properties文件,就可使用文件里的配置变量了。

<properties resource="mybatis.properties"/>mysql

程序注入

  • 最后还有一种咱们在构建SqlSessionFactory的时候从新载入咱们的Properties对象就能够了。另外三者的优先级是从低到高

settings

configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false));
configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
configuration.setDefaultEnumTypeHandler(resolveClass(props.getProperty("defaultEnumTypeHandler")));
configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true));
configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
configuration.setLogPrefix(props.getProperty("logPrefix"));
configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
  • 上面代码是咱们在XMLConfigBuilder解析settings标签的代码。从这段代码中咱们了解到settings子标签。
参数 功能 可选值 默认值
autoMappingBehavior 指定Mybatis应如何自动映射列到字段上。
NONE : 表示取消自动映射
PARTIAL:只会自动映射没有定义嵌套结果集映射的结果集
FULL : 自动映射任意复杂的结果集
NONE、PARTIAL、FULL PARTIAL
autoMappingUnknownColumnBehavior 指定识别到位置列或属性的时间
NONE : 什么都不作
WARNING:日志会报警(前提是日志设置了显示权限)
FAILING : 抛出异常。
NONE, WARNING, FAILING NONE
cacheEnabled 该配置影响的全部映射器中配置的缓存的全局开关 true|false true
proxyFactory 指定Mybatis建立具备延迟加载能力的对象所用到的代理工具未指定时将自动查找 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING not set
lazyLoadingEnabled 延时加载全局开关
开启时:级联对象会延时加载;级联标签中能够经过fetchType来定制覆盖此选项
true|false false
aggressiveLazyLoading 启用时:对任意延迟属性的调用会使带有延迟加载属性的对象分层性质完整加载,反之按需加载 true|false true
multipleResultSetsEnabled 是否容许单一语句返回多结果集 true|false true
useColumnLabel 确切的说当映射找不到参数时会使用列标签(数据库列名)代替别名去映射 true|false true
useGeneratedKeys 容许 JDBC 支持自动生成主键,须要驱动兼容。 若是设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工做(好比 Derby) true|false false
defaultExecutorType 配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新 SIMPLE REUSE BATCH SIMPLE
defaultStatementTimeout 设置超时时间,决定驱动等待数据库响应的秒数 整数 null
defaultFetchSize 设置数据库resultSet读取数据方式,默认所有加载进内存,设置该属性能够设置一次性读多少条数据进内存 整数 null
mapUnderscoreToCamelCase 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的相似映射。 true|false false
safeRowBoundsEnabled -容许在嵌套语句中使用分页 true|false false
localCacheScope 一级缓存。mybatis默认对同一个sqlsession中数据是共享的。一个sqlsession调用两次相同查询实际只会查询一次。就是由于该属性为SESSION , STATEMENT则针对的是每一条sql SESSION|STATEMENT SESSION
jdbcTypeForNull 当没有为参数提供特定的jdbc类型时,为空值则指定JDBC类型。在新增时咱们没有设置参数,这个时候就会根据此参数天长。加入设置VARCHAR,那么咱们新增的数据没传参数则为空字符 NULL|VARCHAR|OTHER OTHER
lazyLoadTriggerMethods 指定具体方法延时加载 方法 equals,clone,hashCode,toString
safeResultHandlerEnabled 容许在嵌套语句中使用分页 true|false true
defaultScriptingLanguage 动态SQL生成的默认语言 org.apache.ibatis.scripting.xmltags.XMLDynamicLanguageDriver
defaultEnumTypeHandler mybatis默认的枚举处理类
callSettersOnNulls 指定当结果集中值为null的时候是否调用映射对象的setter(put)方法。
useActualParamName 容许使用他们的编译后名称来映射,3.4.2后默认true.在xml中#{0}则报错。设置为false,则#{0}表明第一个参数#{n}第n个 true|false true
returnInstanceForEmptyRow 当返回行的全部列都是空时,MyBatis默认返回 null。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集 (如集合或关联)。(新增于 3.4.2) true|false false
logPrefix 指定 MyBatis 增长到日志名称的前缀。

别名

  • 别名是mybatis为咱们项目中类起的一个名字,类名每每会很长因此别名就方便咱们平时的开发。Mybatis为咱们内置了一些类的别名:byte、short、int、long、float、double、boolean、char等基础类型的别名。还有其的封装类型、String,Object,Map,List等等经常使用的类。
    org.apache.ibatis.type.TypeAliasRegistry这个类中帮咱们内置了别名。能够看下。自定义别名也是经过这个类进行注册的。咱们能够经过settings中typeAliases配置的方式结合@Alias。或者扫描包也能够的。

TypeHandler

  • 这个接口就四个方法
public interface TypeHandler<T> {

  /**
   * 设置参数是用到的方法
   */
  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;

}
  • 能够理解成拦截器。它主要拦截的是设置参数和获取结果的两个节点。这个类的做用就是将Java对象和jdbcType进行相互转换的一个功能。一样的在org.apache.ibatis.type.TypeHandlerRegistry这个类中mybatis为咱们提供了内置的TypeHandler。基本上是对于基本数据和分装对象的转换。
  • 下面咱们随便看一个TypeHandler处理细节
public class BooleanTypeHandler extends BaseTypeHandler<Boolean> {

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, Boolean parameter, JdbcType jdbcType)
      throws SQLException {
    ps.setBoolean(i, parameter);
  }

  @Override
  public Boolean getNullableResult(ResultSet rs, String columnName)
      throws SQLException {
    boolean result = rs.getBoolean(columnName);
    return !result && rs.wasNull() ? null : result;
  }

  @Override
  public Boolean getNullableResult(ResultSet rs, int columnIndex)
      throws SQLException {
    boolean result = rs.getBoolean(columnIndex);
    return !result && rs.wasNull() ? null : result;
  }

  @Override
  public Boolean getNullableResult(CallableStatement cs, int columnIndex)
      throws SQLException {
    boolean result = cs.getBoolean(columnIndex);
    return !result && cs.wasNull() ? null : result;
  }
}
  • setParameter是PreparedStatement进行设置成boolean类型。getResult分别经过三种不一样方式获取。在这些方法里咱们能够根据本身也无需求进行控制。常见的控制是枚举的转换。传递参数过程多是枚举的name,可是传递到数据库中要枚举的index.这种需求咱们就能够在TypeHandler中实现。咱们书写的typeHandler以后并不能被识别,还须要咱们在resultMap中的result标签中经过typeHandler指定咱们的自定义Handler.

自定义TypeHandler

  • 承接上文咱们说道枚举的转换。下面咱们仍是已学生类为例。学生中性别以前是boolean类型。如今咱们采用枚举类型。可是数据库中存的仍是数据,01.

EnumTypeHandler

  • 在TypeHandlerRegister类中申明了默认的枚举类处理器是private Class<? extends TypeHandler> defaultEnumTypeHandler = EnumTypeHandler.class;
@Override
public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
  String s = rs.getString(columnName);
  return s == null ? null : Enum.valueOf(type, s);
}
  • 咱们经过这个方法能够看出,这个枚举处理器适合已枚举名称存储的方式


EnumOrdinalTypeHandler

  • 在Enum中还有一个属性oridinal。这个表示枚举中的索引。而后咱们经过查看Mybatis提供的处理器发现有个叫EnumOrdinalTypeHandler。咱们很容易联想到的就是这个处理器是经过枚举的因此做为数据库内容的。在SexEnum中MALE存储到数据库中则为0.注意这个0不是咱们的index.而是MALE的索引。若是将MALE和FEMAEL调换。那么MALE索引则为1.git

  • 由于默认的是EnumTypeHandler。因此想用EnumOrdinalTypeHandler的话咱们要么在resultMap中sex字段指定该处理器。要不就经过配置文件typeHandlers注册进来。(将处理器与Java类进行绑定。mybatis遇到这个Java对象的时候就知道用什么处理器处理)github

<typeHandlers>
    <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.github.zxhtom.enums.SexEnum"/>
</typeHandlers>

SexTypeHandler

  • 上面的不论是经过名称存储仍是经过索引存储都不太知足咱们的需求。咱们想经过咱们的index存储。那么这时候咱们就得自定义处理逻辑了。Mybatis处理器都是继承BaseTypeHandler。由于BaseTypeHandler实现了TypeHandler.因此咱们这里也就继承BaseTypeHandler。
public class SexTypeHandler extends BaseTypeHandler<SexEnum> {


    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, SexEnum parameter, JdbcType jdbcType) throws SQLException {
        ps.setInt(i,parameter.getIndex());
    }

    @Override
    public SexEnum getNullableResult(ResultSet rs, String columnName) throws SQLException {
        int i = rs.getInt(columnName);
        return SexEnum.getSexEnum(i);
    }

    @Override
    public SexEnum getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        int i = rs.getInt(columnIndex);
        return SexEnum.getSexEnum(i);
    }

    @Override
    public SexEnum getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        int i = cs.getInt(columnIndex);
        return SexEnum.getSexEnum(i);
    }
}

typeHandler注意点

  • 在编写自定义处理器的时候咱们得之处Javatype、jdbctype。二者不是必填。但至少得有一个。正常咱们默认javatype是必填的。
  • 填写的方式有三种
    • 经过MappedTypes、MappedJdbcTypes分别指定javatype、jdbctype
    • 经过在mybatis-config.xml中配置typeHandlers进行注解。里面也有这两个属性的配置。
    • 经过在mapper.xml的resultmap中再次指定某个字段的typehandler.
  • TypeHandler为咱们提供了Java到jdbc数据的转换桥梁。极大的方便了咱们平时的开发。让咱们开发期间忽略数据的转换这么糟心的事情。

加入战队sql

# 加入战队

微信公众号

微信公众号

相关文章
相关标签/搜索