Mybatis中关于自定义typeHandler的详细使用以及心得体会-超级详细

2年前 (2022) 程序员胖胖胖虎阿
352 0 0

1. 什么是 typeHandler

typeHandler 是MyBatis框架集成的一个数据类型处理器,用于 java 数据类型 和 数据库类型 之间的互转,当然java对于数据库的操作需要jdbc,所以可以理解为 java数据类型 和 jdbc类型 之间的转换器,专业用词就是 javaTypejdbcType 之间的转换,可以见下表所示:
Mybatis中关于自定义typeHandler的详细使用以及心得体会-超级详细

2. typeHandler的隐式声明

MyBatis 系统已经创建好所常用的 typeHandler。在大部分的情况下无须显式地声明 jdbcType 和 javaType,或者用 typeHandler 去指定对应的字段来实现数据类型转换,因为 MyBatis 系统会自己探测映射的数据类型,来自动选择 typeHandler

3. 自定义typeHandler

虽然 typeHandler 所提供的转换类型很多,但有的时候仍然不能满足我们对于某一字段的转换要求,这时就需要自定义类型处理器。
参考了网上很多资料,大部分都讲的不太明白,以下是自己通过一天的不断测试,总结的心得体会,如有什么错误,欢迎指正。

3.1 需求:将数据库里的 datetime 类型 转换到Java类型是 String,且格式为 “2022/3/12 11:19:34”

如果不自定义类型处理器,Mybatis转换的格式为
数据库Mybatis中关于自定义typeHandler的详细使用以及心得体会-超级详细 java字符串Mybatis中关于自定义typeHandler的详细使用以及心得体会-超级详细

虽然默认处理器可以实现自动转换,但是 java 的时间转换格式不能自定义,所以用自定义处理器来实现

  1. 实现泛型接口TypeHandler<String>的四个方法
/*
* 自定义 数据库dataTime 与 java String 转换
* */
public class StringTypeHandle implements TypeHandler<String> {

//  将java类型 转换成 数据库需要的类型
    public void setParameter(PreparedStatement preparedStatement, int i, String str, JdbcType jdbcType) throws SQLException {
       /*
        * 调用mabatis所集成的处理器转换过去
        * 框架所提供的转换方法更加强大
        * 即在插入和更新数据时在字段处不引用该处理器
        * */
    }

    //  将数据库中类型 转换成java类型
    public String getResult(ResultSet resultSet, String s) throws SQLException {
        Date date = resultSet.getDate(s);
        Time time = resultSet.getTime(s);
        java.util.Date dateTime = new java.util.Date(date.getTime()+time.getTime()+8*60*60*1000);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        return sdf.format(dateTime);
    }
    //  将数据库中类型 转换成java类型
    public String getResult(ResultSet resultSet, int i) throws SQLException {
        Date date = resultSet.getDate(i);
        Time time = resultSet.getTime(i);
        java.util.Date dateTime = new java.util.Date(date.getTime()+time.getTime()+8*60*60*1000);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        return sdf.format(dateTime);
    }
    //  将数据库中类型 转换成java类型
    public String getResult(CallableStatement callableStatement, int i) throws SQLException {
        Date date = callableStatement.getDate(i);
        Time time = callableStatement.getTime(i);
        java.util.Date dateTime = new java.util.Date(date.getTime()+time.getTime()+8*60*60*1000);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        return sdf.format(dateTime);
    }
}
  1. setParameter(PreparedStatement preparedStatement, int i, String str, JdbcType jdbcType) 是将 java数据类型 转换成 数据库需要的类型PreparedStatement preparedStatement是在执行更新或者添加表数据时给占位符 ?设置值,int i表示第几个占位符,即位置,String str是需要处理的字符串,JdbcType jdbcType是数据库的数据类型(目前没发现作用)
  2. String getResult()有三个重载方法,目的都是将 数据库中的类型 转换成 java类型,只是有不同的方式提取数据库的值,可以是根据字段位置,字段名称,存储过程调用等
  1. mybatis-config.xml (mybatis配置文件) 配置文件中进行注册
<typeHandlers>
	<typeHandler handler="com.cyx.entity.StringTypeHandle"></typeHandler>
</typeHandlers>

注意在 <configuration> </configuration> 中的位置顺序

  1. 所需要转换的字段处引用 typeHandler = “com.cyx.entity.StringTypeHandle”(自己的类名)
<mapper namespace="com.cyx.mapper.TestMapper">

    <resultMap id="TestResult" type="testData">
        <result column="createTime" property="createTime" typeHandler="com.cyx.entity.StringTypeHandle"/>
    </resultMap>
    <select id="findAll" resultMap="TestResult">
        select * from test
    </select>

</mapper>
3.2 需求:将 数据库中varchar类型 “-1.201,-1.214,-0.254,…” 转换成java类型 Double[] {-1.201,-1.214,-0.254,…}

知识点:TypeHandler<?>泛型中是引用类型,不能填基本数据类型,基本数据类型要转换成引用类型-包装类,因为实质上都是 Object 的转换,而Object是一个类
具体基本数据类型和引用类型的互相转换,可以看 23.Java之包装类(包装类的分类,装箱,拆箱)

  1. 实现泛型接口TypeHandler<Double[]>的四个方法
/*
 * 自定义 数据库 varchar 转换成 double[]数组
 * */
public class DoubleTypeHandle implements TypeHandler<Double[]> {
    //  将java类型 转换成 数据库需要的类型
    public void setParameter(PreparedStatement preparedStatement, int i, Double[] doubles, JdbcType jdbcType) throws SQLException {
        String s1 = "";
        for (int j = 0; j < doubles.length; j++) {
            if (j != 0)
            {
                s1 += ",";
            }
            s1 += String.valueOf(doubles[j]);
        }
        preparedStatement.setString(i,s1);
    }
    //  将数据库中类型 转换成java类型
    public Double[] getResult(ResultSet resultSet, String s) throws SQLException {
        String s1 = resultSet.getString(s);
        Double points[] = null;
        if (s1 != null) {
            String str[] = s1.split(",");
            points = new Double[str.length];
            for (int j = 0; j < str.length; j++) {
                points[j] = Double.parseDouble(str[j]);
            }
        }
        return points;
    }

    public Double[] getResult(ResultSet resultSet, int i) throws SQLException {
        String s1 = resultSet.getString(i);
        Double points[] = null;
        if (s1 != null) {
            String str[] = s1.split(",");
            points = new Double[str.length];
            for (int j = 0; j < str.length; j++) {
                points[j] = Double.parseDouble(str[j]);
            }
        }
        return points;
    }

    public Double[] getResult(CallableStatement callableStatement, int i) throws SQLException {
        String s1 = callableStatement.getString(i);
        Double points[] = null;
        if (s1 != null) {
            String str[] = s1.split(",");
            points = new Double[str.length];
            for (int j = 0; j < str.length; j++) {
                points[j] = Double.parseDouble(str[j]);
            }
        }
        return points;
    }
}
  1. mybatis-config.xml (mybatis配置文件) 配置文件中进行注册
<!--    注册类型处理器 -->
    <typeHandlers>
        <typeHandler handler="com.cyx.entity.DoubleTypeHandle"></typeHandler>
    </typeHandlers>
  1. 所需要转换的字段处引用 typeHandler = “com.cyx.entity.DoubleTypeHandle” (自己的类名)
<mapper namespace="com.cyx.mapper.TestMapper">

    <insert id="addObj" parameterType="testData">
        insert into test(name,createTime,isOnline,points) values (#{name},#{createTime},#{isOnline},#{points,typeHandler=com.cyx.entity.ArrayTypeHandle})
    </insert>

    <resultMap id="TestResult" type="testData">
        <result column="points" property="points" typeHandler="com.cyx.entity.DoubleTypeHandle"/>
    </resultMap>
    <select id="findAll" resultMap="TestResult">
        select * from test
    </select>

</mapper>

4. 扩充

如果从数据库里取的值想转换成几个不同类型的,但是写几个重复的类型处理器确实会有些繁琐,这时候可以直接实现接口TypeHandler,对 Object o 进行类的判断,再做不同的处理

public class ArrayTypeHandle implements TypeHandler {
//  将java类型 转换成 数据库需要的类型
    public void setParameter(PreparedStatement preparedStatement, int i, Object o, JdbcType jdbcType) throws SQLException {
    
    }

    //  将数据库中类型 转换成java类型
    public Object getResult(ResultSet resultSet, String s) throws SQLException {
        return null;
    }

    public Object getResult(ResultSet resultSet, int i) throws SQLException {
        return null;
    }

    public Object getResult(CallableStatement callableStatement, int i) throws SQLException {
        return null;
    }
}

相关文章

暂无评论

暂无评论...