Mybatis中的TypeHandler是什么?
无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时,都会用类型处理器将获取的值以合适的方式转换成 Java 类型。Mybatis默认为我们实现了许多TypeHandler, 当我们没有配置指定TypeHandler时,Mybatis会根据参数或者返回结果的不同,默认为我们选择合适的TypeHandler处理。
typeHandlers无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。下表描述了一些默认的类型处理器。
提示 从 3.4.5 开始,MyBatis 默认支持 JSR-310(日期和时间 API) 。
使用场景:mybatis在预处理语句(PreparedStatement)中设置一个参数时,或者从结果集(ResultSet)中取出一个值时,都会用到TypeHandler。它的作用就是将java类型(javaType)转化为jdbc类型(jdbcType),或者将jdbc类型(jdbcType)转化为java类型(javaType)。
需求一:
自定义枚举类型的TypeHandler,我们通过User类中有一个属性性别(Sex)类型,来实现数据库存sexcode, 取数据出来是sexname
需求二:
User类中有一个属性叫做interest,这个属性用来描述用户的爱好,它的数据类型是一个List集合,那么我想在把这个List集合存入数据库的时候能够自动的变成{XXX,XXX,XXX}这样一个字符串然后存起来,当我从数据库读取的时候也是读取到这样一个字符串,读取成功之后再自动的将之转为一个List集合,
系统提供的typeHandler能够满足我们日常开发中的大部分需求,如上这两种特殊的需求就需要我们自己去定义typeHandler了
1、自定义Sex枚举类型(需求一)public enum SexEnum {
MALE(1,"男"),
FMALE(0,"女");
private int sexCode;
private String sexName;
private SexEnum(int sexCode, String sexName) {
this.sexCode = sexCode;
this.sexName = sexName;
}
//通过SexCode的值来获取Sex枚举类型
public static SexEnum getSexEnumFromCode(int sexCode) {
if(sexCode == 1) {
return MALE;
}else if(sexCode == 0) {
return FMALE;
}
return null;
}
//get set
}
2、 自定义枚举类型的TypeHandler
自定义typeHandler我们有两种方式,一种是实现TypeHandler接口,还有一种就是继承自BaseTypeHandler类。
@MappedJdbcTypes() 定义的是JdbcType类型,这里的类型不可自己随意定义,必须要是枚举类org.apache.ibatis.type.JdbcType所枚举的数据类型。 @MappedTypes() 定义的是JavaType的数据类型,描述了哪些Java类型可被拦截。
在我们启用了我们自定义的这个TypeHandler之后,数据的读写都会被这个类所过滤 在setNonNullParameter / setParameter方法中,我们重新定义要写往数据库的数据。 另外三个方法中我们将从数据库读出的数据类型进行转换
采用注解 或者 sql映射文件指定 JdbcType 和 JavaType 都可以
1) sex属性类型用自定义Sex枚举类型的TypeHandler(需求一)
public class MySexTypeHandler implements TypeHandler{
@Override
public void setParameter(PreparedStatement ps, int i, SexEnum parameter, JdbcType jdbcType) throws SQLException {
ps.setInt(i, parameter.getSexCode());
}
@Override
public SexEnum getResult(ResultSet rs, String columnName) throws SQLException {
int sexCode = rs.getInt(columnName);
return SexEnum.getSexEnumFromCode(sexCode);
}
@Override
public SexEnum getResult(ResultSet rs, int columnIndex) throws SQLException {
int sexCode = rs.getInt(columnIndex);
return SexEnum.getSexEnumFromCode(sexCode);
}
@Override
public SexEnum getResult(CallableStatement cs, int columnIndex) throws SQLException {
int sexCode = cs.getInt(columnIndex);
return SexEnum.getSexEnumFromCode(sexCode);
}
}
2)interest属性类型用自定义List类型的TypeHandler(需求二) 采用注释
@MappedTypes(List.class)
@MappedJdbcTypes({JdbcType.VARCHAR})
public class MyListTypeHandler extends BaseTypeHandler{
@Override
public void setNonNullParameter(PreparedStatement ps, int i, List parameter, JdbcType jdbcType)
throws SQLException {
if(parameter != null) {
// List集合转字符串
StringBuffer sbBuffer = new StringBuffer();
for(String string : parameter) {
sbBuffer.append(string).append(",");
}
ps.setString(i, sbBuffer.toString().substring(0,sbBuffer.toString().length()-1));
}
}
@Override
public List getNullableResult(ResultSet rs, String columnName) throws SQLException {
if(rs.getString(columnName) != null) {
String[] split = rs.getString(columnName).split(",");
return Arrays.asList(split);
}
return null;
}
@Override
public List getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String[] split = rs.getString(columnIndex).split(",");
return Arrays.asList(split);
}
@Override
public List getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String[] split = cs.getString(columnIndex).split(",");
return Arrays.asList(split);
}
}
3、 数据库 与 java model类
sex属性类型用自定义SexEnum 枚举类型
public class User {
private Integer id;
private String username;
private String pazzword;
private Integer state;
private Date regDate;
private SexEnum sex; // 1:男, 0:女,用枚举
private List interest; //爱好
...}
注意: 获取数据和插入数据 的 配置
id, username, pazzword, state, reg_date, sex, interest
select
from t_user
where id = #{id,jdbcType=INTEGER}
insert into t_user
(username,pazzword,state,reg_date,sex,interest)
values
(#{username},#{pazzword},#{state},#{regDate},
#{sex, jdbcType=INTEGER, javaType=cn.jq.mybatis.enums.SexEnum, typeHandler=cn.jq.mybatis.enums.MySexTypeHandler},
#{interest, typeHandler=cn.jq.mybatis.enums.MyListTypeHandler})
5、在全局配置文件中注册自定义的typeHandler
注意标签配置顺序: 在 set 标签之后
6、测试
1)insert数据
UserMapper userMapper = session.getMapper(UserMapper.class);
List list = new ArrayList();
list.add("足球");
list.add("排球");
list.add("音乐");
User user = new User();
user.setUsername("ad22");
user.setPazzword("pass22");
user.setState(1);
user.setRegDate(new Date());
user.setSex(SexEnum.FMALE);
//user.setInterest(null); //爱好为空,自定义typeHandle做了判断
user.setInterest(list);
userMapper.insertUser(user);
session.commit();
System.out.println(user);
数据库:
2)select 数据
User user1 = userMapper.selectByPrimaryKey(1);
System.out.println(user1);
小结 OK,经过上面的介绍,想必小伙伴对typeHandler的使用已经有一定了解了,总结一下就是读取时的配置要和插入时的配置分开来做,
读取时数据转换我们有两种配置方式,分别是resultMap和在mybatis配置文件中配置typeHandlers,
插入时的配置就是在insert节点中进行配置。
参考文章:
https://blog.csdn.net/u012702547/article/details/54572679
https://www.cnblogs.com/dongying/p/4040435.html