建立TypeHandler

我们知道java有java的数据类型,数据库有数据库的数据类型,那么我们在往数据库中插入数据的时候是如何把java类型当做数据库类型插入数据库,在从数据库读取数据的时候又是如何把数据库类型当做java类型来处理呢?这中间必然要经过一个类型转换。在Mybatis中我们可以定义一个叫做TypeHandler类型处理器的东西,通过它可以实现Java类型跟数据库类型的相互转换。下面将就如何建立自己的TypeHandler做一个简要介绍。

TypeHandler接口

在Mybatis中要实现自己的TypeHandler就需要实现Mybatis为我们提供的TypeHandler接口。在TypeHandler中定义了四个方法:

public interface TypeHandler<T> {  

    /** 

     * 用于定义在Mybatis设置参数时该如何把Java类型的参数转换为对应的数据库类型 

     * @param ps 当前的PreparedStatement对象 

     * @param i 当前参数的位置 

     * @param parameter 当前参数的Java对象 

     * @param jdbcType 当前参数的数据库类型 

     * @throws SQLException 

     */  

    void setParameter(PreparedStatement ps, int i, T parameter,  

           JdbcType jdbcType) throws SQLException;  

    /** 

     * 用于在Mybatis获取数据结果集时如何把数据库类型转换为对应的Java类型 

     * @param rs 当前的结果集 

     * @param columnName 当前的字段名称 

     * @return 转换后的Java对象 

     * @throws SQLException 

     */  

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

    /** 

     * 用于在Mybatis通过字段位置获取字段数据时把数据库类型转换为对应的Java类型 

     * @param rs 当前的结果集 

     * @param columnIndex 当前字段的位置 

     * @return 转换后的Java对象 

     * @throws SQLException 

     */  

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

    /** 

     * 用于Mybatis在调用存储过程后把数据库类型的数据转换为对应的Java类型 

     * @param cs 当前的CallableStatement执行后的CallableStatement 

     * @param columnIndex 当前输出参数的位置 

     * @return 

     * @throws SQLException 

     */  

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

}  

现在假设我们有一个实体对象User,其中有一个属性interests是String数组类型,如下所示:

public class User {  

    private int id;  

    private String name;  

    private int age;  

    private String[] interests;  

    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;  

    }  

    public int getAge() {  

       return age;  

    }  

    public void setAge(int age) {  

       this.age = age;  

    }  

    public String[] getInterests() {  

       return interests;  

    }  

    public void setInterests(String[] interests) {  

       this.interests = interests;  

    }  

    @Override  

    public String toString() {  

       return "User [age=" + age + ", id=" + id + ", interests="  

              + Arrays.toString(interests) + ", name=" + name + "]";  

    }  

}  

我们需要把它以拼接字符串的形式存到数据库中,然后在取出来的时候又把它还原为一个String数组。这个时候我们就可以给它定义一个TypeHandler专门来处理String数组类型和数据库VARCHAR类型的相互转换。在这里我们建立一个名叫StringArrayTypeHandler的TypeHandler,代码如下所示:

package com.tiantian.mybatis.handler;  

import java.sql.CallableStatement;  

import java.sql.PreparedStatement;  

import java.sql.ResultSet;  

import java.sql.SQLException;  

import java.sql.Types;  

import org.apache.ibatis.type.JdbcType;  

import org.apache.ibatis.type.TypeHandler;  

public class StringArrayTypeHandler implements TypeHandler<String[]> {  

       public String[] getResult(ResultSet rs, String columnName)  

                     throws SQLException {  

              String columnValue = rs.getString(columnName);  

              return this.getStringArray(columnValue);  

       }  

       public String[] getResult(ResultSet rs, int columnIndex)  

                     throws SQLException {  

              String columnValue = rs.getString(columnIndex);  

              return this.getStringArray(columnValue);  

       }  

       public String[] getResult(CallableStatement cs, int columnIndex)  

                     throws SQLException {  

              // TODO Auto-generated method stub  

              String columnValue = cs.getString(columnIndex);  

              return this.getStringArray(columnValue);  

       }  

       public void setParameter(PreparedStatement ps, int i, String[] parameter,  

                     JdbcType jdbcType) throws SQLException {  

              if (parameter == null)  

                     ps.setNull(i, Types.VARCHAR);  

              else {  

                     StringBuffer result = new StringBuffer();  

                     for (String value : parameter)  

                            result.append(value).append(",");  

                     result.deleteCharAt(result.length()-1);  

                     ps.setString(i, result.toString());  

              }  

       }  

       private String[] getStringArray(String columnValue) {  

              if (columnValue == null)  

                     return null;  

              return columnValue.split(",");  

       }  

}  

BaseTypeHandler抽象类

在实现自己的TypeHandler时,除了上面提到的实现最原始的接口之外,Mybatis还为我们提供了一个实现了TypeHandler接口的抽象类BaseTypeHandler。所以我们也可以通过继承BaseTypeHandler来实现自己的TypeHandler。

我们先来看一下BaseTypeHandler类的定义:

public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {  

  protected Configuration configuration;  

  public void setConfiguration(Configuration c) {  

    this.configuration = c;  

  }  

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

    if (parameter == null) {  

      if (jdbcType == null) {  

        throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");  

      }  

      try {  

        ps.setNull(i, jdbcType.TYPE_CODE);  

      } catch (SQLException e) {  

        throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " +  

             "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " +  

             "Cause: " + e, e);  

      }  

    } else {  

      setNonNullParameter(ps, i, parameter, jdbcType);  

    }  

  }  

  public T getResult(ResultSet rs, String columnName) throws SQLException {  

    T result = getNullableResult(rs, columnName);  

    if (rs.wasNull()) {  

      return null;  

    } else {  

      return result;  

    }  

  }  

  public T getResult(ResultSet rs, int columnIndex) throws SQLException {  

    T result = getNullableResult(rs, columnIndex);  

    if (rs.wasNull()) {  

      return null;  

    } else {  

      return result;  

    }  

  }  

  public T getResult(CallableStatement cs, int columnIndex) throws SQLException {  

    T result = getNullableResult(cs, columnIndex);  

    if (cs.wasNull()) {  

      return null;  

    } else {  

      return result;  

    }  

  }  

  public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;  

  public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException;  

  public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException;  

  public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException;  

}  

我们可以看到BaseTypeHandler对TypeHandler接口的四个方法做了一个简单的选择,把null值的情况都做了一个过滤,核心的取值和设值的方法还是抽象出来了供子类来实现。使用BaseTypeHandler还有一个好处是它继承了另外一个叫做TypeReference的抽象类,通过TypeReference的getRawType()方法可以获取到当前TypeHandler所使用泛型的原始类型。这对Mybatis在注册TypeHandler的时候是非常有好处的。在没有指定javaType的情况下,Mybatis在注册TypeHandler时可以通过它来获取当前TypeHandler所使用泛型的原始类型作为要注册的TypeHandler的javaType类型,这个在讲到Mybatis注册TypeHandler的方式时将讲到。

当通过继承BaseTypeHandler来实现自己的TypeHandler时,我们的StringArrayTypeHandler应该这样写:

public class StringArrayTypeHandler extends BaseTypeHandler<String[]> {  

    @Override  

    public String[] getNullableResult(ResultSet rs, String columnName)  

           throws SQLException {  

       return getStringArray(rs.getString(columnName));  

    }  

    @Override  

    public String[] getNullableResult(ResultSet rs, int columnIndex)  

           throws SQLException {  

       return this.getStringArray(rs.getString(columnIndex));  

    }  

    @Override  

    public String[] getNullableResult(CallableStatement cs, int columnIndex)  

           throws SQLException {  

       return this.getStringArray(cs.getString(columnIndex));  

    }  

    @Override  

    public void setNonNullParameter(PreparedStatement ps, int i,  

           String[] parameter, JdbcType jdbcType) throws SQLException {  

       //由于BaseTypeHandler中已经把parameter为null的情况做了处理,所以这里我们就不用再判断parameter是否为空了,直接用就可以了  

       StringBuffer result = new StringBuffer();  

       for (String value : parameter)  

           result.append(value).append(",");  

       result.deleteCharAt(result.length()-1);  

       ps.setString(i, result.toString());  

    }  

    private String[] getStringArray(String columnValue) {  

       if (columnValue == null)  

           return null;  

       return columnValue.split(",");  

    }  

}

注册TypeHandler

建立了自己的TypeHandler之后就需要把它注册到Mybatis的配置文件中,让Mybatis能够识别并使用它。注册TypeHandler主要有两种方式,一种是通过在Mybatis配置文件中定义typeHandlers元素的子元素typeHandler来注册;另一种是通过在Mybatis配置文件中定义typeHandlers元素的子元素package来注册。使用typeHandler子元素注册时一次只能注册一个TypeHandler,而使用package子元素注册时,Mybatis会把指定包里面的所有TypeHandler都注册为TypeHandler。使用typeHandler子元素注册时我们需要通过它的handler属性来指明当前要注册的TypeHandler的全名称,这个属性是必须要的。另外还有两个附加属性可以指定,一个是javaType,用以指定对应的java类型;另一个是jdbcType,用以指定对应的jdbc类型。使用package子元素注册时需要我们通过它的name属性来指定要扫描的包,如果这个时候我们也需要指定对应TypeHandler的javaType和jdbcType的话就需要我们在TypeHandler类上使用注解来定义了。Mybatis注册TypeHandler最基本的方式就是建立一个javaType、jdbcType和TypeHandler的对应关系。在使用typeHandler子元素进行注册的时候,有三种类型的注册方式:

1.如果我们指定了javaType和jdbcType,那么Mybatis会注册一个对应javaType和jdbcType的TypeHandler。

2.如果我们只指定了javaType属性,那么这个时候又分两种情况:

(1)如果我们通过注解的形式在TypeHandler类上用@MappedJdbcTypes指定了对应的jdbcType,那么Mybatis会一一注册指定的javaType、jdbcType和TypeHandler的组合,也包括使用这种形式指定了jdbcType为null的情况。现假设我们有如下这样一个StringArrayTypeHandler:

@MappedJdbcTypes({JdbcType.VARCHAR})  

public class StringArrayTypeHandler implements TypeHandler<String[]> {  

    //..中间的实现代码省略了  

    //..  

}  

然后我们在Mybatis的配置文件中这样注册它:

<typeHandlers>  

   <typeHandler handler="com.tiantian.mybatis.handler.StringArrayTypeHandler" javaType="[Ljava.lang.String;"/>  

</typeHandlers>  

则Mybatis在实际注册的时候是以javaType为String数组,jdbcType为VARCHAR来注册StringArrayTypeHandler的。

mybatis typehandler的更多相关文章

  1. mybatis typeHandler类型转换器

    typeHandler类型转换器 在JDBC中,需要在PreparedStatement对象中设置那些已经预编译过的SQL语句的参数.执行SQL后,会通过ResultSet对象获取得到数据库的数据,而 ...

  2. mybatis基础,mybatis配置文件核心组件typeHandler元素

    无论是从预处理语句中设置一个值,还是从结果集里取出一个值,都会用类型处理器将获取的值以合适的方式转换成 Java 类型 可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型 实现 o ...

  3. mybatis 枚举typeHandler

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

  4. 使用Mybatis的TypeHandler加解密数据

    使用Mybatis的TypeHandler加解密数据 一.背景 二.解决方案 三.需求 四.实现思路 1.编写一个实体类,凡是此实体类的数据都表示需要加解密的 2.编写一个加解密的`TypeHandl ...

  5. TypeHandler的简单实例

    转自:http://ccchhhlll1988-163-com.iteye.com/blog/1420149 TypeHandler是MyBatis config文件中可选的配置选项,其可以对实体属性 ...

  6. MyBatis里字段到枚举类型的转换/映射

    一.简介 我们在用MyBatis里,很多时间有这样一个需求:bean里有个属性是枚举,在DB存储时我们想存的枚举的代号,从DB拿出来时想直接映射成目标枚举类型,也即代号字段与Java枚举类的相互类型转 ...

  7. MyBatis里json型字段到Java类的映射

    一.简介 我们在用MyBatis里,很多时间有这样一个需求:bean里有个属性是非基本数据类型,在DB存储时我们想存的是json格式的字符串,从DB拿出来时想直接映射成目标类型,也即json格式的字符 ...

  8. mybatis(二)

    一级缓存和二级缓存 mybatis一二级缓存测试实例: package com.atguigu.mybatis.test; import java.io.IOException; import jav ...

  9. 深入理解MyBatis的原理(三):配置文件用法(续)

    前言:前文讲解了 MyBatis 的配置文件一部分用法,本文将继续讲解 MyBatis 的配置文件的用法. 目录 1.typeHandler 类型处理器 2.ObjectFactory 3.插件 4. ...

随机推荐

  1. macaca 环境搭建篇,(web 和安卓)

    appium研究一段时间,感觉appium太不稳定了, 后来听说了阿里开源了macaca,那么我就想尝尝鲜,啥都不说,我感觉还是赶紧上手搭建环境吧. macaca介绍: Macaca是一套完整的自动化 ...

  2. C语言格式化输入输出

    %i和%d之间的区别 作为匹配整数的转换说明,printf格式串中两者并没有区别,但是在scanf格式串中%d只能匹配十位制整数,而%i可以匹配八进制(前缀为0,如086).十进制或十六进制(前缀0x ...

  3. UCOSii项目在NIOSii上的移植

    概览 本次使用Altera公司的NIOS II软核. 使用Quatus工具生成BSP并利用BSP打包工具生成UCOSII嵌入环境. 手动书写LCD驱动与显示函数,对UCOS II加入简单图像显示接口. ...

  4. springboot配置swagger2

    .在pom.xml里添加jar包: <dependency> <groupId>io.springfox</groupId> <artifactId>s ...

  5. 英语学习案例分析APP 201421123108 王坤彬

    第一部分.调研,测评 1.第一次使用经验. 我使用的时候苹果手机下载的必应软件.第一次使用感觉还好,但是知名度比较低,比不上喜马拉雅听书软件,这里我就做两者的对比.首先界面以及种类明显逼格更差点.必应 ...

  6. 团队作业8——第二次项目冲刺(Beta阶段)第三天

    BETA阶段冲刺第三天 1.当天站立式会议 2.每个人的工作 (1)昨天已完成的工作: 编写页面讨论 (2)今天计划完成的工作: 完成编写页面 (3)工作中遇到的困难: 验证码正确度 (4)每个人的贡 ...

  7. 测试与发布(Alpha版本)

    [Alpha阶段]测试报告 1.测试找出的BUG (1).这种情况刷新就好 (2).文件必须10个才行,多余10个的部分不会进入查重的部分,少于会出错: (3).文件保存在d:\files,由于有些原 ...

  8. Swing-JRadioButton用法-入门

    JRadioButton是Swing中的单选框.所谓单选框是指,在同一个组内虽然有多个单选框存在,然而同一时刻只能有一个单选框处于选中状态.它就像收音机的按钮,按下一个时此前被按下的会自动弹起,故因此 ...

  9. 201521123087 《Java程序设计》第4周学习总结

    1. 本周学习总结 2. 书面作业 注释的应用使用类的注释与方法的注释为前面编写的类与方法进行注释,并在Eclipse中查看.(截图)                                 ...

  10. 201521123085 《Java程序设计》 第3周学习总结

    1. 本周学习总结 2. 书面作业 1.代码阅读 public class Test1 { private int i = 1;//这行不能修改 private static int j = 2; p ...