Mybatis是一个优秀的持久层框架,它提供了丰富的功能来简化数据库操作。在Mybatis中,TypeHandler是用于处理Java对象与数据库字段之间的类型转换的组件。自定义TypeHandler可以帮助我们处理一些特殊的数据类型或者自定义的数据类型。
自定义TypeHandler需要实现org.apache.ibatis.type.TypeHandler接口,并重写其中的方法。主要包括以下几个方法:
- setParameter:用于将Java对象转换为JDBC参数进行设置。
- getResult:用于将数据库字段的值转换为Java对象进行返回。
- getResult(CallableStatement cs, int columnIndex):用于将数据库字段的值转换为Java对象进行返回,支持存储过程。
- getResult(ResultSet rs, String columnName):用于将数据库字段的值转换为Java对象进行返回,通过字段名获取值。
- getResult(ResultSet rs, int columnIndex):用于将数据库字段的值转换为Java对象进行返回,通过字段索引获取值。
下面是一个自定义TypeHandler的示例代码:
public class MyCustomTypeHandler implements TypeHandler<MyCustomType> {@Overridepublic void setParameter(PreparedStatement ps, int i, MyCustomType parameter, JdbcType jdbcType) throws SQLException {// 将Java对象转换为JDBC参数进行设置ps.setString(i, parameter.toString());}@Overridepublic MyCustomType getResult(ResultSet rs, String columnName) throws SQLException {// 将数据库字段的值转换为Java对象进行返回String value = rs.getString(columnName);return new MyCustomType(value);}@Overridepublic MyCustomType getResult(ResultSet rs, int columnIndex) throws SQLException {// 将数据库字段的值转换为Java对象进行返回String value = rs.getString(columnIndex);return new MyCustomType(value);}@Overridepublic MyCustomType getResult(CallableStatement cs, int columnIndex) throws SQLException {// 将数据库字段的值转换为Java对象进行返回,支持存储过程String value = cs.getString(columnIndex);return new MyCustomType(value);}
}
在Mybatis的配置文件中,我们需要注册自定义的TypeHandler。可以通过在标签中添加子标签来进行配置,示例如下:
<typeHandlers><typeHandler handler="com.example.MyCustomTypeHandler"/>
</typeHandlers>
这样,Mybatis就会在需要处理MyCustomType类型的字段时,使用我们自定义的TypeHandler进行类型转换。
如果项目是使用SpringBoot开发,也可以直接在类配置器的获取sqlSessionFactory实例的方法中进行注入。
其实Mybatis默认提供了一些基本类型的类型转换器,我们可以参照这些类型转换器去自定义。
在这个包目录下:org.apache.ibatis.type
我们随便看一个实现类:BigDecimalTypeHandler
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.apache.ibatis.type;import java.math.BigDecimal;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class BigDecimalTypeHandler extends BaseTypeHandler<BigDecimal> {public BigDecimalTypeHandler() {}public void setNonNullParameter(PreparedStatement ps, int i, BigDecimal parameter, JdbcType jdbcType) throws SQLException {ps.setBigDecimal(i, parameter);}public BigDecimal getNullableResult(ResultSet rs, String columnName) throws SQLException {return rs.getBigDecimal(columnName);}public BigDecimal getNullableResult(ResultSet rs, int columnIndex) throws SQLException {return rs.getBigDecimal(columnIndex);}public BigDecimal getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {return cs.getBigDecimal(columnIndex);}
}
很简单,就是继承了BaseTypeHandler
接口,然后实现其中的抽象方法就可以了。
我们可以自己实现这个BigDecimal的类型转换器,比如我这里自定义了一个BigDecimal类型转换器,默认将查询的结果小数点后面的0去掉。
package com.au.sa.storeRebate.common.handler;import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.springframework.stereotype.Component;import java.math.BigDecimal;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;/*** @author xiaohuihui* @creteTime 2024-05-01 10:53* @description*/
@Component
public class BigDecimalTypeHandler extends BaseTypeHandler<BigDecimal> {@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, BigDecimal parameter, JdbcType jdbcType) throws SQLException {ps.setBigDecimal(i, parameter);}@Overridepublic BigDecimal getNullableResult(ResultSet rs, String columnName) throws SQLException {return rs.getBigDecimal(columnName).stripTrailingZeros();}@Overridepublic BigDecimal getNullableResult(ResultSet rs, int columnIndex) throws SQLException {return rs.getBigDecimal(columnIndex).stripTrailingZeros();}@Overridepublic BigDecimal getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {return cs.getBigDecimal(columnIndex).stripTrailingZeros();}
}
然后在Mybatis数据源的配置类中,注入Handler的包扫描路径就可以了。
@Primary@Bean("sqlSessionFactory")public SqlSessionFactory sqlSessionFactory(@Qualifier("master") DataSource dataSource, @Qualifier("mybatisPlusInterceptor") MybatisPlusInterceptor mybatisPlusInterceptor) throws Exception {MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();sqlSessionFactory.setDataSource(dataSource);LOGGER.info("数据库连接池信息:{}", ((HikariDataSource)dataSource).getIdleTimeout());GlobalConfig globalConfig=new GlobalConfig();globalConfig.setMetaObjectHandler(metaObjectHandler);sqlSessionFactory.setGlobalConfig(globalConfig);MybatisConfiguration configuration = new MybatisConfiguration();configuration.setMapUnderscoreToCamelCase(true);if (Objects.equals(isShowSql, true)) {configuration.setLogImpl(StdOutImpl.class);}configuration.setCacheEnabled(false);configuration.addInterceptor(mybatisPlusInterceptor);sqlSessionFactory.setConfiguration(configuration);sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));sqlSessionFactory.setTypeHandlersPackage("com.au.sa.storeRebate.common.handler");return sqlSessionFactory.getObject();}
就是这一行代码:
sqlSessionFactory.setTypeHandlersPackage("com.au.sa.storeRebate.common.handler");
也可以采用这种形式:
@Resourceprivate BigDecimalTypeHandler bigDecimalTypeHandler;sqlSessionFactory.setTypeHandlers(bigDecimalTypeHandler);
实现的效果:
返回的结果自动将小数点后面的0去除了。