在做开发的时候,经常会遇到关于数据类型的问题,mybatis本身已经为我们提供了许多typeHandler了,系统提供的typeHandler能够满足我们日常开发中的大部分需求,但是有时候也会遇到需要自己定义typeHandler的情况,比如说我在数据库中有一个WfWorkSpace表,其中有一个字段Handler记录了当前处理人的信息,在数据库中改字段类型是varchar,但是在java代码中这个Handler的数据结构是一个实体类,如下所示:
@Data
public class Handler implements POJO {
/**
*
*/
private static final long serialVersionUID = 1L;
private Set users;
private Set groups;
}
在mybatis的xml文件中有如下的映射关系
WfWorkSpace实体类为:
public class WfWorkSpace extends LongIdVO {
/**
*
*/
private static final long serialVersionUID = -5555413588381268957L;
private Long id;
private Handler handler;
这个时候就需要涉及到自定义一个mybatis的typeHandler问题了
第一步,实现一个集成自BaseTypeHandler的公共数据格式处理的类JsonTypeHandler:
public class JsonTypeHandler extends BaseTypeHandler {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType)
throws SQLException {
ps.setString(i, JSON.toJSONString(parameter));
}
@Override
public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
return JSON.parseObject(rs.getString(columnName), getRawType());
}
@Override
public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return JSON.parseObject(rs.getString(columnIndex), getRawType());
}
@Override
public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return JSON.parseObject(cs.getString(columnIndex), getRawType());
}
}
第二步,自定义TypeHandler类型:
@Component
@MappedTypes(Handler.class)
public class HandlerTypeHandler extends JsonTypeHandler {
}
另外我们还可以实现下面两种场景,比如我有一个Java中的Date数据类型,我想将之存到数据库的时候存成一个1970年至今的毫秒数,怎么实现?再比如我有一个User类,User类中有一个属性叫做interest,这个属性用来描述用户的爱好,它的数据类型是一个List集合,那么我想在把这个List集合存入数据库的时候能够自动的变成{XXX,XXX,XXX}
这样一个字符串然后存起来,当我从数据库读取的时候也是读取到这样一个字符串,读取成功之后再自动的将之转为一个List集合
1:日期转换
@MappedJdbcTypes({JdbcType.VARCHAR})
@MappedTypes({Date.class})
public class MyDateTypeHandler extends BaseTypeHandler {
public void setNonNullParameter(PreparedStatement preparedStatement, int i, Date date, JdbcType jdbcType) throws SQLException {
preparedStatement.setString(i, String.valueOf(date.getTime()));
}
public Date getNullableResult(ResultSet resultSet, String s) throws SQLException {
return new Date(resultSet.getLong(s));
}
public Date getNullableResult(ResultSet resultSet, int i) throws SQLException {
return new Date(resultSet.getLong(i));
}
public Date getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return callableStatement.getDate(i);
}
}
自定义好了typeHandler之后,接下来我们需要在userMapper.xml中进行简单的配置,首先我们可以像上文说的,配置resultMap,如下:
配置resultMap的时候我们指定了javaType和jdbcType,同时也指定了处理的typeHandler,然后在select中使用这个resultMap:
但是这种方式有一个缺点那就是只适用于查询操作,即在查询的过程中系统会启用我们自定义的typeHandler,会将秒数转为Date对象,但是在插入的时候却不会启用我们自定义的typeHandler,想要在插入的时候启用自定义的typeHandler,需要我们在insert节点中简单配置一下,如下:
INSERT INTO user4(username,password,regTime) VALUES (#{username},#{password},#{regTime,javaType=Date,jdbcType=VARCHAR,typeHandler=org.sang.db.MyDateTypeHandler})
也可以只配置javaType和jdbcType,如下:
INSERT INTO user4(username,password,regTime) VALUES (#{username},#{password},#{regTime,javaType=Date,jdbcType=VARCHAR})
或者只配置typeHandler:
INSERT INTO user4(username,password,regTime) VALUES (#{username},#{password},#{regTime,typeHandler=com.db.MyDateTypeHandler})
这三种效果都是一样的,都是在插入的时候将数据Date对象转为秒数
2:List集合的转换
@MappedTypes(List.class)
@MappedJdbcTypes({JdbcType.VARCHAR})
public class MyListTypeHandler extends BaseTypeHandler> {
public void setNonNullParameter(PreparedStatement preparedStatement, int i, List strings, JdbcType jdbcType) throws SQLException {
//1.List集合转字符串
StringBuffer sb = new StringBuffer();
for (String string : strings) {
sb.append(string).append(",");
}
//2.设置给ps
preparedStatement.setString(i, sb.toString().substring(0, sb.toString().length() - 1));
}
public List getNullableResult(ResultSet resultSet, String s) throws SQLException {
String[] split = resultSet.getString(s).split(",");
return Arrays.asList(split);
}
public List getNullableResult(ResultSet resultSet, int i) throws SQLException {
String[] split = resultSet.getString(i).split(",");
return Arrays.asList(split);
}
public List getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
String[] split = callableStatement.getString(i).split(",");
return Arrays.asList(split);
}
}
查询:
插入:
INSERT INTO person(interest) VALUES (#{interest,typeHandler=com.db.MyListTypeHandler})
List集合存入数据库之后变成这样:
读取出来之后又自动转为List集合了,下图是查询操作,实体类,和查询结果: