1. 什么是 typeHandler
typeHandler 是MyBatis框架集成的一个数据类型处理器,用于 java 数据类型 和 数据库类型 之间的互转,当然java对于数据库的操作需要jdbc,所以可以理解为 java数据类型 和 jdbc类型 之间的转换器,专业用词就是 javaType 与 jdbcType 之间的转换,可以见下表所示:
2. typeHandler的隐式声明
MyBatis 系统已经创建好所常用的 typeHandler。在大部分的情况下无须显式地声明 jdbcType 和 javaType,或者用 typeHandler 去指定对应的字段来实现数据类型转换,因为 MyBatis 系统会自己探测映射的数据类型,来自动选择 typeHandler
3. 自定义typeHandler
虽然 typeHandler 所提供的转换类型很多,但有的时候仍然不能满足我们对于某一字段的转换要求,这时就需要自定义类型处理器。
参考了网上很多资料,大部分都讲的不太明白,以下是自己通过一天的不断测试,总结的心得体会,如有什么错误,欢迎指正。
3.1 需求:将数据库里的 datetime 类型 转换到Java类型是 String,且格式为 “2022/3/12 11:19:34”
如果不自定义类型处理器,Mybatis转换的格式为
数据库 java字符串
虽然默认处理器可以实现自动转换,但是 java 的时间转换格式不能自定义,所以用自定义处理器来实现
- 实现泛型接口
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);
}
}
setParameter(PreparedStatement preparedStatement, int i, String str, JdbcType jdbcType)
是将 java数据类型 转换成 数据库需要的类型,PreparedStatement preparedStatement
是在执行更新或者添加表数据时给占位符 ?设置值,int i
表示第几个占位符,即位置,String str
是需要处理的字符串,JdbcType jdbcType
是数据库的数据类型(目前没发现作用)String getResult()
有三个重载方法,目的都是将 数据库中的类型 转换成 java类型,只是有不同的方式提取数据库的值,可以是根据字段位置,字段名称,存储过程调用等
- 在 mybatis-config.xml (mybatis配置文件) 配置文件中进行注册
<typeHandlers>
<typeHandler handler="com.cyx.entity.StringTypeHandle"></typeHandler>
</typeHandlers>
注意在 <configuration> </configuration> 中的位置顺序
- 所需要转换的字段处引用 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之包装类(包装类的分类,装箱,拆箱)
- 实现泛型接口
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;
}
}
- 在 mybatis-config.xml (mybatis配置文件) 配置文件中进行注册
<!-- 注册类型处理器 -->
<typeHandlers>
<typeHandler handler="com.cyx.entity.DoubleTypeHandle"></typeHandler>
</typeHandlers>
- 所需要转换的字段处引用 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;
}
}