本篇文章用来记录作者自己的学习过程 ,在这个过程中参考了以下作者的文章:
http://elim.iteye.com/blog/1847854#_Toc353481987
TypeHandler的由来
java有java的数据类型,数据库有数据库的类型,大家都知道在jdbc中我们两者之间的转换都需要自己写代码实现,typeHandler就是为了解决两者之间的自动的转换
TypeHandler接口介绍
typeHandler就是为了解决两者之间的自动的转换,那么它需要做一下几件事情
参数设置的转换(jdbc中的形式 stmt.setInt(1, 1) 不熟悉的话建议去回忆一下jdbc)
获取到结果集的转换: 数据库表字段的名称 表字段的位置 除了简单sql还有存储过程
以上需要做几件事 ,就定义了几种方法
TypeHandler接口代码如下:
public interface TypeHandler<T> {
/**
* 类型转换接口 这个能体现怎么设计一个接口 是自己比较欠缺的
* java 与数据库 之间的转换 (抽象一下 需要做哪几件事情)
* 参数设置的转换
* 获取到结果集的转换: 数据库表字段的名称 表字段的位置 除了简单sql还有存储过程
* @param ps
* @param i
* @param parameter
* @param jdbcType
* @throws SQLException
*/
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
/**
*
* @param rs
* @param columnName
* @return
* @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;
}
我们有一个类JiKeUser,里边有个属性interests,是个String[],存入数据库是它拼接,我们怎么来实现这个转换过程呢
JikeUser源码:
public class JiKeUser {
private int id;
private String userName;
private String password;
//需要把它以拼接字符串的形式存到数据库中,然后在取出来的时候又把它还原为一String 数组
private String[] interests;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String[] getInterests() {
return interests;
}
public void setInterests(String[] interests) {
this.interests = interests;
}
@Override
public String toString() {
return "User [ id=" + id + ", interests="
+ Arrays.toString(interests) + ", userName=" + userName + "]";
}
创建StringArrayTypeHandler继承TypeHandler,用来实现java到数据库的互相转换
/**
* 自己实现的一个TypeHandler 类 用于java 数据库类型的转换
* @author hc
*
*/
public class StringArrayTypeHandler implements TypeHandler<String[]>{
@Override
public void setParameter(PreparedStatement ps, int i, String[] parameter,
JdbcType jdbcType) throws SQLException {
if(parameter==null){
ps.setNull(i, Types.VARCHAR);
}else{
//在这里边具体实现 java对象到数据库的转换
StringBuffer sb=new StringBuffer();
for(int j=0;i<parameter.length;j++)
sb.append(parameter[j]).append(",");
ps.setString(i,sb.toString());
}
}
@Override
public String[] getResult(ResultSet rs, String columnName) throws SQLException {
String columnValue=rs.getString(columnName);
return getStringArray(columnValue);
}
@Override
public String[] getResult(ResultSet rs, int columnIndex) throws SQLException {
String columnValue=rs.getString(columnIndex);
return getStringArray(columnValue);
}
@Override
public String[] getResult(CallableStatement cs, int columnIndex)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
/**
* 字符串转换为数组
* @param columnValue
* @return
*/
private String[] getStringArray(String columnValue) {
if (columnValue == null)
return null;
return columnValue.split(",");
}
接下来我们就需要注册我们实现的Typehandler,注册分为两种方式:
a.在配置文件中定义typehandlers的子元素typehanlder来注册,该方式一次只能注册一个,另外还有两个属性需要指定,javatype java的类型 jdbctype数据库中的类型,除了在xml 文件直接配置上边的两个属性以外,还可以用注解的形式在StringArrayTypeHandler 类开头指定类型(@MappedJdbcTypes({JdbcType.VARCHAR}) )
b.在在配置文件中定义typehandlers的子元素package来注册,该种方式可以注册包下边的所有typehandler,jdbctype和javatype只能通过注解的形式指定
下边以XML 举例 完成java数组 和数据库Varchar的注册
<typeHandlers>
<typeHandler handler="my.book.business.StringArrayTypeHandler" javaType="[Ljava.lang.String;" jdbcType="VARCHAR"/>
</typeHandlers>
则Mybatis在实际注册的时候是以javaType为String数组,jdbcType为VARCHAR来注册StringArrayTypeHandler的。
mybatis自动获取我们刚刚注册的typehandler
jikeUser.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="/">
<resultMap type="my.book.pojo.JiKeUser" id="jikeUser">
<result property="id" column="id"/>
<result property="userName" column="use_name"/>
<result property="password" column="password"/>
<result column="interests" property="interests" javaType="[Ljava.lang.String;" jdbcType="VARCHAR"/>
</resultMap>
<select id="findById" parameterType="int" resultMap="jikeUser">
select * from jikeUser where id=#{id}
</select>
</mapper>
这个时候Mybatis就会到已经注册了的TypeHandler中寻找到能处理javaType和jdbcType对应的类型转换的TypeHandler来进行处理。在这里就会找到我们注册的StringArrayTypeHandler.
文章写道这里,上边只是一种最基本的注册获取方式,除了可以用注解代替外一下罗列的情况也是可以的
A. 不动StringArrayTypeHandler的注册信息,jikeUser.xml修改如下
<result column="interests" property="interests" jdbcType="VARCHAR"/>
过程分析:首先它发现我们的interests没有指定javaType,这个时候它就会通过我们指定的类型User和属性interests获取User类的interests属性对应的java类型,即String数组,再拿着获取到的javaType和我们指定的jdbcType即VARCHAR去寻找对应的TypeHandler,这个时候就找到了我们之前以String数组和VARCHAR注册好的StringArrayTypeHandler来处理interests的类型转换
B 注册和查找的jdbctype 不设置 这时候按照 javatype jdbctype=null typeHandler注册和查找
C。结合AB完成最简单,在A的基础上 注册和查找的jdbctype 不设置