Mybatis之typeHandler类型转换器

引言:在JDBC中,需要在PreparedStatement对象中设置那些已经预编译过的SQlL语句的参数。执行SQL后,会通过ResultSet对象获取得到数据库的数据,而这些在Mybatis是根据数据的类型通过typeHandler来实现的。

在typeHandler中,分为jdbcType和javatype,其中jdbcType用于定义数据库类型,而javaType用于定义Java类型,那么typeHandler的作用就是承担jdbcTypr和javaType之间的相互转换

Mybatis之typeHandler类型转换器_第1张图片
很多情况下我们并不需要去配置typeHandler、jdbcType和javaType,因为在Mybatis会探测应该使用什么类型的typeHandler去处理,也就是说Mybatis内部定义了许多常用的typeHandler。但是有些场景是无法探测到,比如那些需要使用自定义枚举场景,或者数据库使用特殊数据类型的场景,这些情况我们可以使用自定义的typeHandler去处理类型之间的转换问题。

一、系统定义的typeHandler

下面给大家列出几个常用简单的typeHander
Mybatis之typeHandler类型转换器_第2张图片这些都是Mybatis系统已经创建好的TypeHandler转换器,在大部分情况下无需显式地声明jdbcType和javaType,或者用typeHandler去指定对应的typeHandler来实现数据类型的转换,因为Mybatis系统会自动探测。

二、自定义TypeHandler

1、分析Typehandlet源码

在Mybatis中typeHandler都要实现接口org.apache.ibatis.type.TypeHandler,下面根据源码简单分析一下。

public interface TypeHandler {

  void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;

  T getResult(ResultSet rs, String columnName) throws SQLException;

  T getResult(ResultSet rs, int columnIndex) throws SQLException;

  T getResult(CallableStatement cs, int columnIndex) throws SQLException;

}

  • T是泛型,专指javaType,比如我们需要String的时候,那么实现类可以写为 implements TypeHandler< String >.
  • setParameter方法,是使用typeHandler通过PreparedStatement对象进行设置SQL参数的时候使用的具体方法。其中:ps是PreparedStatement对象;i是参数在SQL语句中的下标;jdbcType是数据库类型
  • 其中的3个getResult方法,它的作用是从JDBC结果集中获取数据进行转换,使用列名(columnName)或下标(columeIdex)获取数据库的数据。最后一个getResulte方法是存储过程专用的。

2、自定义typeHandler(以String为例)

从系统定义的typeHandler中可以知道,要实现typeHandler就需要去实现接口Typehandler,或者继承BaseTypeHandler(实际上,BaseTypehandler实现了typeHandler接口)。在这里,我们直接实现TypeHandler接口,代码如下:

package com.ydj.utils;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.apache.log4j.Logger;


public class MyTypeHandler implements TypeHandler{
	
	//定义一个日志
	Logger log = Logger.getLogger(MyTypeHandler.class);

	@Override
	public String getResult(ResultSet rs, String columnName) throws SQLException {
		String result = rs.getString(columnName);
		log.info("读取string参数1【"+result+"】");
		return result;
	}

	@Override
	public String getResult(ResultSet rs, int columnIdex) throws SQLException {
		String result = rs.getString(columnIdex);
		log.info("读取string参数2【"+result+"】");
		return result;
	}

	@Override
	public String getResult(CallableStatement cs, int columnIdex) throws SQLException {
		String result = cs.getString(columnIdex);
		log.info("读取string参数3【"+result+"】");
		return result;
	}

	@Override
	public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
		log.info("设置string参数【"+parameter+"】");
		ps.setString(i, parameter);
	}
}

3、在代码中使用自定义typeHandler

方式一:

(1)首先在mybatis-config.xml配置typeHandlers

	
	
		
	

配置完后系统才会读取它,这样注册后,当jdbcTypeHandler和javaTypeHandler能与MyTypeHandler对应的时候,它就会启动MyTypeHandler。

注意:在mybatis-config.xml配置属性时,是有顺序的,不然在Mybatis启动阶段就会发生异常,导致程序无法运行。顺序如下:

                   < configuration >     				//配置
                   < properties/>						//属性
                   < settings />	 					//设置
                   < typeAliases >	 					//类型别名
                   < typeHandlers/>						//类型处理器
                   < objectFactory/>					//对象工厂
                   < plugins> //插件
                   < environments>						//配置环境
                   		< environment>					//环境变量
                   			< transactionManager />		//事务管理器
                  			< dataSource/>				//数据源
                 		  < environment>
                   < environments>
                   < databaseIdProvider/> 				//数据库厂商标识
                   < mappers/> 							//映射器

(2)在映射文件 xxxMapper.xml配置


		
		
		

方式二

直接在映射文件xxxMapper.xml里面配置,代码如下:


		
		
		

总结

实现自定义typeHandler:
要么指定了与自定义typeHandler一致的jdbcType和javaType(见方式一)
要么直接使用typeHandler指定的具体实现类(全限定名)(见方式二)
当然,两者也可一起使用,最好在mybatis-congif.xml里面配置typeHandlers属性

----mybatis.config.xml代码片段----
	
	
		
	

----xxxMapper.xml代码片段----
	
		
		
		
	

4、多个自定义typeHandler在同一个包中

有时候由于枚举类型很多,系统需要的typeHandler也会很多,如果采用配置也会很麻烦,这个时候可以考虑使用包扫描的形式。

(1)假定自定义的typeHandler类在com.ydj.utils下

----mybatis.config.xml代码片段----
	
	
		
	

如果这样注册就没法指定jdbcType和javaType了,不过我们可以使用注解来处理它们。

(2)注解表明jdbcType和javaType

@MappedTypes(String.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class MyTypeHandler implements TypeHandler{
......
}

三、枚举typeHandler(重点)

在绝大多数情况下,typeHandler因为枚举而使用,Mybatis已经定义了两个类作为枚举类型的支持,这两个类分别为:

  • EnumOrdinalTypeHandler
  • EnumTypeHandler

因为它们的作用不大,所以大部分情况下,我们都不用它们,不过我们还是要稍微了解一下它们的用法。

先来建一个性别枚举类——SexEnum

package com.ydj.model;

public enum SexEnum {
	MALE(1, "男"),
	FEMALE(0, "女");
	private int id;
	private String name;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	SexEnum(int id, String name){
		this.id = id;
		this.name = name;
	}
	
	public static SexEnum getSexById(int id){	
		for (SexEnum sex : SexEnum.values()) {
			if(sex.getId() == id){
				return sex;
			}
		}
		return null;
	}
}

用户表类代码:

package com.ydj.model;

public class User {
	
	private Integer uid;
	private String uname;
	private String upwd;
	private SexEnum sex;
	
	public Integer getUid() {
		return uid;
	}
	public void setUid(Integer uid) {
		this.uid = uid;
	}
	
	public String getUname() {
		return uname;
	}
	public void setUname(String uname) {
		this.uname = uname;
	}
	public
	String getUpwd() {
		return upwd;
	}
	public void setUpwd(String upwd) {
		this.upwd = upwd;
	}
	
	public SexEnum getSex() {
		return sex;
	}
	public void setSex(SexEnum sex) {
		this.sex = sex;
	}
	
	@Override
	public String toString() {
		return "User [uid=" + uid + ", uname=" + uname + ", upwd=" + upwd + ", sex=" + sex + "]";
	}
}

1、用EnumOrdinalTypeHandler实现

它是Mybatis根据枚举数组下标索引的方式进行匹配的,它要求数据库返回一个整数作为其下标,它会根据下标找到对应的枚举类型。

	----xxxMapper.xml部分代码----
	
		
		
		
		
		
	
	

2、用EnumTypeHandler实现

它会把使用的名称转化为对应的枚举,比如它会根据数据库返回的字符串“MALE”,进行Enum.valueOf(SexEnum.class, “MALE”);转换。


		
		
		
		
		
	
	

3、自定义枚举typeHandler

package com.ydj.utils;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.apache.ibatis.type.TypeHandler;

import com.ydj.model.SexEnum;

@MappedTypes(SexEnum.class)
@MappedJdbcTypes(JdbcType.INTEGER)
public class SexEnumTypeHandler implements TypeHandler{

	@Override
	public SexEnum getResult(ResultSet rs, String ColumnName) throws SQLException {
		int id = rs.getInt(ColumnName);
		return SexEnum.getSexById(id);
	}

	@Override
	public SexEnum getResult(ResultSet rs, int ColumnIndex) throws SQLException {
		int id = rs.getInt(ColumnIndex);
		return SexEnum.getSexById(id);
	}

	@Override
	public SexEnum getResult(CallableStatement cs, int ColumnIndex) throws SQLException {
		int id = cs.getInt(ColumnIndex);
		return SexEnum.getSexById(id);
	}

	@Override
	public void setParameter(PreparedStatement ps, int i, SexEnum parameter, JdbcType jdbcType) throws SQLException {
		ps.setInt(i, parameter.getId());
	}
}

实现

----xxxMapper.xml部分代码
	
		
		
		
		
	
	

你可能感兴趣的:(SSM)