MyBatis - 配置(4) - typeHandlers

官方文档:http://www.mybatis.org/mybatis-3/zh/configuration.html#typeHandlers

 

1. 示例

假设我们有这样一个需求:

  • 有个POJO:Address,包含省市区信息;数据库与之对应的列是:address varchar(100)
  • Address作为参数保存至数据库时,格式为:省 市 区
  • 数据库address映射到Address时,自动设置省市区信息

当然我们可以搞个PO类,将Address的省市区信息拼接后作为参数保存至数据库、数据库直接映射到PO中,再手动切割保存到Address中。这里只是为了使用Mybatis时,多提供一种解决思路,学习MyBatis中使用自定义的TypeHandler来处理上述需求。

(1)User、Address

public class User {
    private Integer id;
    private String userName;
    private Address address;
    
    // getter、setter略
}
public class Address {
	
    public Address() {
    }

    public Address(String address) {
        if (Objects.nonNull(address) && address.length() > 0) {
            String[] addrArray = address.split(" ");
            this.province = addrArray[0];
            this.city = addrArray[1];
            this.area = addrArray[2];
        }
    }

    private String province;
    private String city;
    private String area;
    
    // getter、setter略
}

(2)自定义类型处理器

可以通过实现 org.apache.ibatis.type.TypeHandler 接口, 或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler, 然后可以选择性地将它映射到一个 JDBC 类型。

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;

/**
 * Address <-> VARCHAR
 * */
@MappedJdbcTypes(value = JdbcType.VARCHAR, includeNullJdbcType = true)
@MappedTypes(Address.class)
public class AddressTypeHandler extends BaseTypeHandler<Address> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Address parameter, JdbcType jdbcType)
        throws SQLException {
        // 格式:省 市 区
        ps.setString(i, parameter.getProvince() + " " + parameter.getCity() + " " + parameter.getArea());
    }

    @Override
    public Address getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return new Address(rs.getString(columnName));
    }

    @Override
    public Address getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return new Address(rs.getString(columnIndex));
    }

    @Override
    public Address getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return new Address(cs.getString(columnIndex));
    }	
}

mybatis-config.xml配置:

<!-- mybatis-config.xml -->
<typeHandlers>
    <package name="com.momo.mybatis.typehandler"/>
</typeHandlers>

<!-- 或 typeHandler标签 -->
<typeHandlers>
    <typeHandler handler="com.momo.mybatis.typehandler.AddressTypeHandler"/>
</typeHandlers>

(3)UserMapper.xml

<resultMap>标签中使用,用于查询时映射处理。此时java类型是已知的(从结果类型中获得),但是JDBC类型是未知的。各种情况如下:

  • 指定typeHandler属性:使用指定的处理器处理参数以及映射结果
  • 未指定typeHandler、jdbcType属性:使用javaType=[TheJavaType], jdbcType=null寻找合适的处理器
  • 未指定typeHandler、指定jdbcType属性,使用javaType=[TheJavaType], jdbcType=[TheJdbcType]寻找合适的处理器

一个或多个类型处理器:

  • 假如找到多个处理器,那么优先选用@MappedJdbcTypes注解有includeNullJdbcType=true的处理器,该属性值默认false。如果仍有多个满足条件,选用最后一个注册的处理器。
  • 若只找到一个处理器,那么即使没有includeNullJdbcType=true,也会使用该处理器
<resultMap type="User" id="userMap">
    <id property="id" column="id"/>
    <result property="userName" column="user_name"/>
    <result property="address" column="user_address" jdbcType="VARCHAR"/>
</resultMap>

若是作为参数使用,如新增、更新等,处理同上

<insert id="insert" parameterType="User">
    insert into t_user (user_name, user_address) 
    values(#{userName}, #{address,jdbcType=VARCHAR})
</insert>

 

注:

(1)通过类型处理器的泛型,MyBatis 可以知道该类型处理器处理的 Java 类型,有两种方法改变:

  • mybatis配置文件中,类型处理器的配置元素<typeHandler  javaType="xxx">上通过 javaType 属性指定
  • 在类型处理器的类上增加一个 @MappedTypes 注解来指定与其关联的 Java 类型列表。 如果在 javaType 属性中也同时指定,则注解方式将被忽略

(2)两种方式来指定被关联的 JDBC 类型:

  • mybatis配置文件中,类型处理器的配置元素<typeHandler  jdbcType="xxx">通过jdbcType 属性指定
  • 在类型处理器的类上增加一个 @MappedJdbcTypes 注解来指定与其关联的 JDBC 类型列表。 如果在 jdbcType 属性中也同时指定,则注解方式将被忽略。

(3)在使用<package name="com.momo.handler"/>注册类型处理器时,只能通过注解方式来指定 JDBC 的类型。

 

2. MyBatis内置的类型处理器

官方文档copy过来的,当做笔记用。。

无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。下表描述了一些默认的类型处理器。

提示: 从 3.4.5 开始,MyBatis 默认支持 JSR-310(日期和时间 API) 。

类型处理器Java 类型JDBC 类型
BooleanTypeHandlerjava.lang.Boolean, boolean数据库兼容的 BOOLEAN
ByteTypeHandlerjava.lang.Byte, byte数据库兼容的 NUMERIC 或 BYTE
ShortTypeHandlerjava.lang.Short, short数据库兼容的 NUMERIC 或 SHORT INTEGER
IntegerTypeHandlerjava.lang.Integer, int数据库兼容的 NUMERIC 或 INTEGER
LongTypeHandlerjava.lang.Long, long数据库兼容的 NUMERIC 或 LONG INTEGER
FloatTypeHandlerjava.lang.Float, float数据库兼容的 NUMERIC 或 FLOAT
DoubleTypeHandlerjava.lang.Double, double数据库兼容的 NUMERIC 或 DOUBLE
BigDecimalTypeHandlerjava.math.BigDecimal数据库兼容的 NUMERIC 或 DECIMAL
StringTypeHandlerjava.lang.StringCHAR, VARCHAR
ClobReaderTypeHandlerjava.io.Reader-
ClobTypeHandlerjava.lang.StringCLOB, LONGVARCHAR
NStringTypeHandlerjava.lang.StringNVARCHAR, NCHAR
NClobTypeHandlerjava.lang.StringNCLOB
BlobInputStreamTypeHandlerjava.io.InputStream-
ByteArrayTypeHandlerbyte[]数据库兼容的字节流类型
BlobTypeHandlerbyte[]BLOB, LONGVARBINARY
DateTypeHandlerjava.util.DateTIMESTAMP
DateOnlyTypeHandlerjava.util.DateDATE
TimeOnlyTypeHandlerjava.util.DateTIME
SqlTimestampTypeHandlerjava.sql.TimestampTIMESTAMP
SqlDateTypeHandlerjava.sql.DateDATE
SqlTimeTypeHandlerjava.sql.TimeTIME
ObjectTypeHandlerAnyOTHER 或未指定类型
EnumTypeHandlerEnumeration TypeVARCHAR-任何兼容的字符串类型,存储枚举的名称(而不是索引)
EnumOrdinalTypeHandlerEnumeration Type任何兼容的 NUMERIC 或 DOUBLE 类型,存储枚举的索引(而不是名称)。
InstantTypeHandlerjava.time.InstantTIMESTAMP
LocalDateTimeTypeHandlerjava.time.LocalDateTimeTIMESTAMP
LocalDateTypeHandlerjava.time.LocalDateDATE
LocalTimeTypeHandlerjava.time.LocalTimeTIME
OffsetDateTimeTypeHandlerjava.time.OffsetDateTimeTIMESTAMP
OffsetTimeTypeHandlerjava.time.OffsetTimeTIME
ZonedDateTimeTypeHandlerjava.time.ZonedDateTimeTIMESTAMP
YearTypeHandlerjava.time.YearINTEGER
MonthTypeHandlerjava.time.MonthINTEGER
YearMonthTypeHandlerjava.time.YearMonthVARCHAR or LONGVARCHAR
JapaneseDateTypeHandlerjava.time.chrono.JapaneseDateDATE

 

你可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。 具体做法为:实现 org.apache.ibatis.type.TypeHandler 接口, 或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler, 然后可以选择性地将它映射到一个 JDBC 类型。比如:

// ExampleTypeHandler.java
@MappedJdbcTypes(JdbcType.VARCHAR)
public class ExampleTypeHandler extends BaseTypeHandler<String> {

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

  @Override
  public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
    return rs.getString(columnName);
  }

  @Override
  public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
    return rs.getString(columnIndex);
  }

  @Override
  public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
    return cs.getString(columnIndex);
  }
}
<!-- mybatis-config.xml -->
<typeHandlers>
    <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>
</typeHandlers>

使用这个的类型处理器将会覆盖已经存在的处理 Java 的 String 类型属性和 VARCHAR 参数及结果的类型处理器。 要注意 MyBatis 不会窥探数据库元信息来决定使用哪种类型,所以你必须在参数和结果映射中指明那是 VARCHAR 类型的字段, 以使其能够绑定到正确的类型处理器上。 这是因为:MyBatis 直到语句被执行才清楚数据类型。

通过类型处理器的泛型,MyBatis 可以得知该类型处理器处理的 Java 类型,不过这种行为可以通过两种方法改变:

  • 在类型处理器的配置元素(typeHandler element)上增加一个 javaType 属性(比如:javaType="String");
  • 在类型处理器的类上(TypeHandler class)增加一个 @MappedTypes 注解来指定与其关联的 Java 类型列表。 如果在 javaType 属性中也同时指定,则注解方式将被忽略。

可以通过两种方式来指定被关联的 JDBC 类型:

  • 在类型处理器的配置元素上增加一个 jdbcType 属性(比如:jdbcType="VARCHAR");
  • 在类型处理器的类上(TypeHandler class)增加一个 @MappedJdbcTypes 注解来指定与其关联的 JDBC 类型列表。 如果在 jdbcType 属性中也同时指定,则注解方式将被忽略。

当决定在ResultMap中使用某一TypeHandler时,此时java类型是已知的(从结果类型中获得),但是JDBC类型是未知的。 因此Mybatis使用javaType=[TheJavaType], jdbcType=null的组合来选择一个TypeHandler。 这意味着使用@MappedJdbcTypes注解可以限制TypeHandler的范围,同时除非显式的设置,否则TypeHandler在ResultMap中将是无效的。 如果希望在ResultMap中使用TypeHandler,那么设置@MappedJdbcTypes注解的includeNullJdbcType=true即可。 然而从Mybatis 3.4.0开始,如果只有一个注册的TypeHandler来处理Java类型,那么它将是ResultMap使用Java类型时的默认值(即使没有includeNullJdbcType=true)。

最后,可以让 MyBatis 为你查找类型处理器:

<!-- mybatis-config.xml -->
<typeHandlers>
    <package name="org.mybatis.example"/>
</typeHandlers>

注意在使用自动检索(autodiscovery)功能的时候,只能通过注解方式来指定 JDBC 的类型。

你可以创建一个能够处理多个类的泛型类型处理器。为了使用泛型类型处理器, 需要增加一个接受该类的 class 作为参数的构造器,这样在构造一个类型处理器的时候 MyBatis 就会传入一个具体的类。

//GenericTypeHandler.java
public class GenericTypeHandler<E extends MyObject> extends BaseTypeHandler<E> {

  private Class<E> type;

  public GenericTypeHandler(Class<E> type) {
    if (type == null) throw new IllegalArgumentException("Type argument cannot be null");
    this.type = type;
  }
  ...

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
mybatis-config.xml是MyBatis的核心配置文件,用于配置MyBatis的全局信息和运行时行为。该文件包含了数据库连接信息和MyBatis所需的各种特性设置和属性。在实际开发,我们通常会将数据库连接参数单独配置在db.properties文件,然后在mybatis-config.xml加载db.properties的属性值,这样就不需要在mybatis-config.xml硬编码数据库连接参数。\[1\] mybatis-config.xml的结构包括: 1. configuration:MyBatis配置信息 2. properties:可以配置在Java属性配置文件的属性 3. settings:修改MyBatis在运行时的行为方式的设置 4. typeAliases:为Java类型命名一个别名(简称) 5. typeHandlers:类型处理器 6. objectFactory:对象工厂 7. plugins:插件 8. environments:环境配置 9. environment:环境变量 10. transactionManager:事务管理器 11. dataSource:数据源 12. mappers:映射器配置mybatis-config.xml,可以使用<typeAliases>标签来定义别名。可以通过单个别名定义或批量别名定义来为Java类型命名别名。批量别名定义可以扫描指定包下的类,将类名作为别名(首字母大写或小写都可以)。\[3\] 总之,mybatis-config.xml是MyBatis的核心配置文件,用于配置全局信息和运行时行为,包含了数据库连接信息和各种特性设置和属性。可以通过配置文件来加载数据库连接参数,避免在配置文件硬编码。同时,还可以使用<typeAliases>标签来定义Java类型的别名。 #### 引用[.reference_title] - *1* *3* [mybatis-config.xml文件的详情](https://blog.csdn.net/qq_60261230/article/details/126524763)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Mybatis-config.xml配置文件基础配置详解](https://blog.csdn.net/qq_43795348/article/details/109553684)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值