MyBatis中自定义typeHandler

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<SexEnum>{

	@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<List<String>>{

	@Override
	public void setNonNullParameter(PreparedStatement ps, int i, List<String> 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<String> 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<String> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
		String[] split = rs.getString(columnIndex).split(",");
		return Arrays.asList(split);
	}

	@Override
	public List<String> 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<String> interest; //爱好

...}

  

4、在sql映射文件中进行配置

 注意: 获取数据和插入数据 的 配置

  <resultMap id="BaseResultMap" type="cn.jq.mybatis.model.User">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="username" jdbcType="VARCHAR" property="username" />
    <result column="pazzword" jdbcType="VARCHAR" property="pazzword" />
    <result column="state" jdbcType="INTEGER" property="state" />
    <result column="reg_date" jdbcType="TIMESTAMP" property="regDate" />
    <result column="sex" property="sex" 
    		jdbcType="INTEGER" 
    		javaType="cn.jq.mybatis.enums.SexEnum"
    		typeHandler="cn.jq.mybatis.enums.MySexTypeHandler"/>
    <result column="interest" property="interest" 
    		typeHandler="cn.jq.mybatis.enums.MyListTypeHandler"/>
  </resultMap>
  
  <sql id="Base_Column_List">
    id, username, pazzword, state, reg_date, sex, interest
  </sql>
  
  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from t_user
    where id = #{id,jdbcType=INTEGER}
  </select>


  	<insert id="insertUser" >
		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})
	</insert>

5、在全局配置文件中注册自定义的typeHandler

    注意标签配置顺序: 在 set 标签之后

	<typeHandlers>
		<typeHandler handler="cn.jq.mybatis.enums.MyListTypeHandler" />
		<typeHandler handler="cn.jq.mybatis.enums.MySexTypeHandler" />
	</typeHandlers>

6、测试

1)insert数据

			UserMapper userMapper = session.getMapper(UserMapper.class);
			
			List<String> list = new ArrayList<String>();
                        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

猜你喜欢

转载自blog.csdn.net/qq_42402854/article/details/84374122