mybatis的类型转换器TypeHandler

本文介绍如何在MyBatis中使用自定义TypeHandler进行Java类型与数据库类型的转换,包括TypeHandler接口详解、自定义TypeHandler实现步骤及示例代码。

TypeHandler简介

在Mybatis中可以定义一个TypeHandler类型,通过它可以实现Java类型跟数据库类型的相互转换。

TypeHandler接口

public interface TypeHandler<T> {

  void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;

  /**
   * Gets the result.
   *
   * @param rs
   *          the rs
   * @param columnName
   *          Colunm name, when configuration <code>useColumnLabel</code> is <code>false</code>
   * @return the result
   * @throws SQLException
   *           the SQL exception
   */
  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接口实现了4个方法,熟悉jdbc应该从方法定义就可以看懂这写接口方法的意思。
不过多解释了,如果不熟悉还是多写写原生jdbc

Mybatis还为我们提供一个实现了TypeHandler接口的抽象类BaseTypeHandler。所以我们也可以通过继承BaseTypeHandler来实现自己的TypeHandler。

  // 继承TypeReference主要提供了一个方法用来获取父类的泛型类型
public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {

  /**
   * @deprecated Since 3.5.0 - See https://github.com/mybatis/mybatis-3/issues/1203. This field will remove future.
   */
  @Deprecated
  protected Configuration configuration;

  /**
   * Sets the configuration.
   *
   * @param c
   *          the new configuration
   * @deprecated Since 3.5.0 - See https://github.com/mybatis/mybatis-3/issues/1203. This property will remove future.
   */
  @Deprecated
  public void setConfiguration(Configuration c) {
    this.configuration = c;
  }

  @Override
  public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
    if (parameter == null) {
      if (jdbcType == null) {
        throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
      }
      try {
        ps.setNull(i, jdbcType.TYPE_CODE);
      } catch (SQLException e) {
        throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . "
              + "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. "
              + "Cause: " + e, e);
      }
    } else {
      try {
        setNonNullParameter(ps, i, parameter, jdbcType);
      } catch (Exception e) {
        throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . "
              + "Try setting a different JdbcType for this parameter or a different configuration property. "
              + "Cause: " + e, e);
      }
    }
  }

  @Override
  public T getResult(ResultSet rs, String columnName) throws SQLException {
    try {
      return getNullableResult(rs, columnName);
    } catch (Exception e) {
      throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set.  Cause: " + e, e);
    }
  }

  @Override
  public T getResult(ResultSet rs, int columnIndex) throws SQLException {
    try {
      return getNullableResult(rs, columnIndex);
    } catch (Exception e) {
      throw new ResultMapException("Error attempting to get column #" + columnIndex + " from result set.  Cause: " + e, e);
    }
  }

  @Override
  public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
    try {
      return getNullableResult(cs, columnIndex);
    } catch (Exception e) {
      throw new ResultMapException("Error attempting to get column #" + columnIndex + " from callable statement.  Cause: " + e, e);
    }
  }

  public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;

  /**
   * Gets the nullable result.
   *
   * @param rs
   *          the rs
   * @param columnName
   *          Colunm name, when configuration <code>useColumnLabel</code> is <code>false</code>
   * @return the nullable result
   * @throws SQLException
   *           the SQL exception
   */
  public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException;

  public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException;

  public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException;

}

public abstract class TypeReference<T> {

  private final Type rawType;
//子类调用父类构造器时调用getSuperclassTypeParameter方法获取rawType
  protected TypeReference() {
    rawType = getSuperclassTypeParameter(getClass());
  }

  Type getSuperclassTypeParameter(Class<?> clazz) {
  // 主要为获取父类泛型及父类类型,Type是接口实现类是ParameterizedTypeImpl
    Type genericSuperclass = clazz.getGenericSuperclass();
    if (genericSuperclass instanceof Class) {
      // try to climb up the hierarchy until meet something useful
      if (TypeReference.class != genericSuperclass) {
        return getSuperclassTypeParameter(clazz.getSuperclass());
      }

      throw new TypeException("'" + getClass() + "' extends TypeReference but misses the type parameter. "
        + "Remove the extension or add a type parameter to it.");
    }
	// 获取泛型类型,如
    Type rawType = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];
    // TODO remove this when Reflector is fixed to return Types
    if (rawType instanceof ParameterizedType) {
      rawType = ((ParameterizedType) rawType).getRawType();
    }

    return rawType;
  }

  public final Type getRawType() {
    return rawType;
  }

  @Override
  public String toString() {
    return rawType.toString();
  }

}

在这里插入图片描述
在这里插入图片描述

自定义TypeHandler类型

1、定义表结构

CREATE TABLE dept (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(255) DEFAULT NULL,
loc varchar(255) DEFAULT NULL,
list varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;

pom以来

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>parent-mybatis</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>mybatis-demo1</artifactId>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.5</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>


        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

</project>

2、定义实体

package com.lhl.demo1;


import java.util.List;

public class Dept {

  

    private int id;

    private String name;

    private String loc;

    private List<String> list;

    public List<String> getList() {
        return list;
    }

    public Dept setList(List<String> list) {
        this.list = list;
        return this;
    }

    public int getId() {
        return id;
    }

    public Dept setId(int id) {
        this.id = id;
        return this;
    }

    public String getName() {
        return name;
    }

    public Dept setName(String name) {
        this.name = name;
        return this;
    }

    public String getLoc() {
        return loc;
    }

    public Dept setLoc(String loc) {
        this.loc = loc;
        return this;
    }
    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Dept{");
        sb.append("id=").append(id);
        sb.append(", name='").append(name).append('\'');
        sb.append(", loc='").append(loc).append('\'');
        sb.append(", list=").append(list);
        sb.append('}');
        return sb.toString();
    }
}

3、mybatis配置文件及mapper文件

<?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>
    <typeHandlers>

        <typeHandler handler="com.lhl.demo1.MyTypeHandler" javaType="List" jdbcType="VARCHAR"></typeHandler>
    </typeHandlers>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis-test"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="DeptMapper.xml"/>
    </mappers>
</configuration>
<?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.lhl.demo1.DeptMapper">
    <insert id="insertDept">
        insert into dept(name, loc, list)
         // 配置typeHandler
        values (#{name}, #{loc}, #{list,javaType=List,jdbcType=VARCHAR,typeHandler=com.lhl.demo1.MyTypeHandler})
    </insert>

 // 配置typeHandler
    <resultMap id="selectDeptMap" type="com.lhl.demo1.Dept">
        <result column="list" property="list" typeHandler="com.lhl.demo1.MyTypeHandler"></result>
    </resultMap>
    <select id="selectDept" resultMap="selectDeptMap">
        select *
        from dept
    </select>
   
  
    </resultMap>

</mapper>

mapper接口

package com.lhl.demo1;

import java.util.List;


public interface DeptMapper {

    void insertDept();

    public List<Dept> selectDept();

}

自定义TypeHandler写法

package com.lhl.demo1;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;


@MappedJdbcTypes(JdbcType.VARCHAR)
@MappedTypes(List.class)
public class MyTypeHandler extends BaseTypeHandler<List> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, List parameter, JdbcType jdbcType) throws SQLException {
        String  str = String.valueOf(parameter.stream().collect(Collectors.joining(",")));
        ps.setString(i,str);
    }

    @Override
    public List getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String result = rs.getString(columnName);
        return Arrays.asList(result.split(","));
    }

    @Override
    public List getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return null;
    }

    @Override
    public List getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return null;
    }
}

1.@MappedJdbcTypes定义是JdbcType类型,必须要是枚举类org.apache.ibatis.type.JdbcType所枚举的数据类型

2.@MappedTypes定义的是JavaType的数据类型,描述哪些Java类型可被拦截。

将TypeHandler注册到mybatis中

<!--需要在别名标签之后-->
  <typeHandlers>

        <typeHandler handler="com.lhl.demo1.MyTypeHandler" javaType="List" jdbcType="VARCHAR"></typeHandler>
    </typeHandlers>
<!--或者通过包扫描的方式,注册包下所有的TypeHandler-->
<typeHandlers>
        <package name="com.lhl.demo1"/>
    </typeHandlers>

在Mapper中配置

 <insert id="insertDept">
        insert into dept(name, loc, list)
         // 配置typeHandler
        values (#{name}, #{loc}, #{list,javaType=List,jdbcType=VARCHAR,typeHandler=com.lhl.demo1.MyTypeHandler})
    </insert>
    
 // 配置typeHandler
    <resultMap id="selectDeptMap" type="com.lhl.demo1.Dept">
        <result column="list" property="list" typeHandler="com.lhl.demo1.MyTypeHandler"></result>
    </resultMap>
    <select id="selectDept" resultMap="selectDeptMap">
        select *
        from dept
    </select>

测试类

package com.lhl.demo1;

import org.apache.ibatis.executor.result.DefaultResultHandler;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;


public class Test01 {
    SqlSession sqlSession = null;

    @BeforeEach
    public void before(){

        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        sqlSession = sqlSessionFactory.openSession();
    }

    @Test
    public void test1(){
        Dept dept =new Dept();
        dept.setLoc("湖北");
        dept.setName("金融事业单位");
        dept.setList(Arrays.asList("1","2","3333"));
        int insertDept = sqlSession.insert("insertDept", dept);
        sqlSession.commit();
    }

    @Test
    public void test2(){

        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        System.out.println(mapper.selectDept());
    }


}

插入时的结果
在这里插入图片描述
查询结果:
在这里插入图片描述

TypeHandlerRegistry

自定义的TypeHandler起作用主要依赖TypeHandlerRegistry进行注册
register方法定义了一部分mybatis自己的类型转换方式,自己实现的typeHandler最终也是调用的register方法来进行注册的。
如:register(List.class,new MyTypeHandler() );
register(JdbcType.VARCHAR,new MyTypeHandler() );
对应到@MappedJdbcTypes(JdbcType.VARCHAR)
@MappedTypes(List.class)

 register(Boolean.class, new BooleanTypeHandler());
    register(boolean.class, new BooleanTypeHandler());
    register(JdbcType.BOOLEAN, new BooleanTypeHandler());
    register(JdbcType.BIT, new BooleanTypeHandler());

    register(Byte.class, new ByteTypeHandler());
    register(byte.class, new ByteTypeHandler());
    register(JdbcType.TINYINT, new ByteTypeHandler());

    register(Short.class, new ShortTypeHandler());
    register(short.class, new ShortTypeHandler());
    register(JdbcType.SMALLINT, new ShortTypeHandler());

    register(Integer.class, new IntegerTypeHandler());
    register(int.class, new IntegerTypeHandler());
    register(JdbcType.INTEGER, new IntegerTypeHandler());

    register(Long.class, new LongTypeHandler());
    register(long.class, new LongTypeHandler());

    register(Float.class, new FloatTypeHandler());
    register(float.class, new FloatTypeHandler());
    register(JdbcType.FLOAT, new FloatTypeHandler());

    register(Double.class, new DoubleTypeHandler());
    register(double.class, new DoubleTypeHandler());
    register(JdbcType.DOUBLE, new DoubleTypeHandler());

    register(Reader.class, new ClobReaderTypeHandler());
    register(String.class, new StringTypeHandler());
    register(String.class, JdbcType.CHAR, new StringTypeHandler());
    register(String.class, JdbcType.CLOB, new ClobTypeHandler());
    register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
    register(String.class, JdbcType.LONGVARCHAR, new StringTypeHandler());
    register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
    register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
    register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
    register(JdbcType.CHAR, new StringTypeHandler());
    register(JdbcType.VARCHAR, new StringTypeHandler());
    register(JdbcType.CLOB, new ClobTypeHandler());
    register(JdbcType.LONGVARCHAR, new StringTypeHandler());
    register(JdbcType.NVARCHAR, new NStringTypeHandler());
    register(JdbcType.NCHAR, new NStringTypeHandler());
    register(JdbcType.NCLOB, new NClobTypeHandler());

    register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
    register(JdbcType.ARRAY, new ArrayTypeHandler());

    register(BigInteger.class, new BigIntegerTypeHandler());
    register(JdbcType.BIGINT, new LongTypeHandler());

    register(BigDecimal.class, new BigDecimalTypeHandler());
    register(JdbcType.REAL, new BigDecimalTypeHandler());
    register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
    register(JdbcType.NUMERIC, new BigDecimalTypeHandler());

    register(InputStream.class, new BlobInputStreamTypeHandler());
    register(Byte[].class, new ByteObjectArrayTypeHandler());
    register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
    register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
    register(byte[].class, new ByteArrayTypeHandler());
    register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
    register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
    register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
    register(JdbcType.BLOB, new BlobTypeHandler());

    register(Object.class, unknownTypeHandler);
    register(Object.class, JdbcType.OTHER, unknownTypeHandler);
    register(JdbcType.OTHER, unknownTypeHandler);

    register(Date.class, new DateTypeHandler());
    register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
    register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
    register(JdbcType.TIMESTAMP, new DateTypeHandler());
    register(JdbcType.DATE, new DateOnlyTypeHandler());
    register(JdbcType.TIME, new TimeOnlyTypeHandler());

    register(java.sql.Date.class, new SqlDateTypeHandler());
    register(java.sql.Time.class, new SqlTimeTypeHandler());
    register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());

    register(String.class, JdbcType.SQLXML, new SqlxmlTypeHandler());

    register(Instant.class, new InstantTypeHandler());
    register(LocalDateTime.class, new LocalDateTimeTypeHandler());
    register(LocalDate.class, new LocalDateTypeHandler());
    register(LocalTime.class, new LocalTimeTypeHandler());
    register(OffsetDateTime.class, new OffsetDateTimeTypeHandler());
    register(OffsetTime.class, new OffsetTimeTypeHandler());
    register(ZonedDateTime.class, new ZonedDateTimeTypeHandler());
    register(Month.class, new MonthTypeHandler());
    register(Year.class, new YearTypeHandler());
    register(YearMonth.class, new YearMonthTypeHandler());
    register(JapaneseDate.class, new JapaneseDateTypeHandler());

    // issue #273
    register(Character.class, new CharacterTypeHandler());
    register(char.class, new CharacterTypeHandler());
<think>我们正在讨论MyBatis-Plus中配置TypeHandler时使用别名的问题。根据用户的问题,我们需要指导如何在MyBatis-Plus中为TypeHandler配置别名。在MyBatis中,TypeHandler用于处理Java类型和JDBC类型之间的转换。有时,我们可能希望为自定义的TypeHandler设置一个别名,以便在映射文件中方便地引用。在MyBatis-Plus中,我们可以通过多种方式配置TypeHandler,其中使用别名的方式与Mybatis类似。步骤:1.自定义TypeHandler:首先需要编写自己的TypeHandler,实现MybatisTypeHandler接口或继承BaseTypeHandler。2.为TypeHandler设置别名:在Mybatis的配置中,我们可以通过类型别名(typeAliases)来为TypeHandler设置别名。3.在映射文件中使用别名:在定义ResultMap或参数映射时,使用别名来引用TypeHandler。但是,在MyBatis-Plus中,我们通常使用注解配置,也可以使用XML配置。参考引用[1]中提到了配置mybatis-config.xml,因此我们可以考虑在mybatis-config.xml中配置别名。示例:步骤1:自定义TypeHandler例如,我们有一个自定义的TypeHandler用于处理List类型:```javapublic classListTypeHandler extendsBaseTypeHandler<List<String>>{//实现方法}```步骤2:在mybatis-config.xml中配置别名在<typeAliases>标签下,为TypeHandler设置别名: ```xml<typeAliases><!--其他别名配置--><typeAliastype="com.example.handler.ListTypeHandler"alias="ListTypeHandler"/></typeAliases> ```步骤3:在映射文件中使用在ResultMap中指定某个列使用这个TypeHandler:```xml<result column="tags" property="tags" typeHandler="ListTypeHandler"/>```另外,MyBatis-Plus也支持通过注解来配置TypeHandler。在实体类的字段上使用@TableField注解指定typeHandler: ```java@TableField(typeHandler =ListTypeHandler.class) privateList<String> tags; ```但是,这里直接使用了类名,并没有使用别名。那么,如果我们想用别名怎么办?实际上,在注解中不能直接使用别名,而是必须使用Class对象。因此,在注解方式下,我们无法使用别名。所以,使用别名主要是在XML映射文件中使用。另外,我们还可以在MyBatis-Plus的全局配置中通过配置typeHandler来注册,但这并不是别名的方式。注意:在MyBatis中,我们还可以通过扫描包的方式来注册TypeHandler,这样就不需要为每个TypeHandler单独配置别名。但是,如果我们需要在XML中引用,那么别名可以简化配置。总结:1.在XML配置中使用别名:在mybatis-config.xml中配置别名,然后在XML映射文件中使用别名引用TypeHandler。2.在注解方式下,无法使用别名,只能直接指定TypeHandler的类。因此,如果用户需要在XML映射文件中使用简短的别名来引用TypeHandler,可以按照上述步骤配置。参考引用[4]中提到了数据库连接的配置,虽然不直接相关,但提醒我们在配置数据库连接时要注意细节。生成相关问题:1.如何在MyBatis-Plus中自定义TypeHandler?2. MyBatis-Plus中如何配置全局的TypeHandler?3.在MyBatis-Plus中,如何通过注解方式指定TypeHandler?4.使用TypeHandler时,如何解决数据库时区问题(如引用[4]中提到的时区问题)?注意:用户的问题集中在“别名”的使用上,因此我们主要解答别名配置的方法。</think>### MyBatis-Plus 中配置 TypeHandler 使用别名的方法 在 MyBatis-Plus 中,通过别名配置 TypeHandler 需要以下步骤: #### 1. **自定义 TypeHandler** 首先创建自定义 TypeHandler 类(以处理 List<String> 类型为例): ```java public class ListTypeHandler extends BaseTypeHandler<List<String>> { @Override public void setNonNullParameter(...) { // 实现JDBC参数设置逻辑 } @Override public List<String> getNullableResult(...) { // 实现结果集转换逻辑 } } ``` #### 2. **配置别名(关键步骤)** 在 `mybatis-config.xml` 中注册别名: ```xml <typeAliases> <!-- 为TypeHandler设置别名 --> <typeAlias type="com.example.handler.ListTypeHandler" alias="ListHandler"/> </typeAliases> ``` #### 3. **在映射中使用别名** ##### 方式1:XML 映射文件 ```xml <resultMap id="userMap" type="User"> <result column="tags" property="tags" typeHandler="ListHandler"/> </resultMap> ``` ##### 方式2:注解方式(需结合 XML 别名) ```java public class User { @TableField(typeHandler = ListHandler.class) // 使用别名 private List<String> tags; } ``` #### 4. **全局配置(可选)** 在 MyBatis-Plus 配置类中全局注册: ```java @Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 添加其他拦截器... return interceptor; } // 注册TypeHandler @Bean public ConfigurationCustomizer configurationCustomizer() { return configuration -> { configuration.getTypeHandlerRegistry().register(ListHandler.class); // 使用别名 }; } } ``` #### 注意事项: 1. **别名作用域** 别名仅在 MyBatis 配置文件作用域内有效,需确保别名在 `mybatis-config.xml` 中正确定义[^1]。 2. **依赖冲突** 如遇 `ClassNotFoundException`,检查是否缺少 `mybatis-typehandlers-jsr310` 等依赖(类似引用[3]中的依赖问题)。 3. **JDBC 参数** 数据库连接需正确配置参数,如 MySQL 时区设置(参考引用[4]): ```properties spring.datasource.url=jdbc:mysql:///db?serverTimezone=Asia/Shanghai ``` 4. **优先级规则** - 字段注解 > XML 映射 > 全局注册 - 自定义 TypeHandler 优先于内置处理器 > **最佳实践**:对于复杂类型处理,建议结合 `@MappedTypes` 和 `@MappedJdbcTypes` 注解声明处理器作用范围,减少显式配置。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值