建立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. ionic实战系列(一):ionic的开发环境配置和编译、发布

    我的ionic实战系列是基于<<Ionic实战>>[美]Jeremy Wilken著-这本书的读书笔记,有诸多借鉴,不详细的地方请参考书籍本身的内容. 1.1技术栈模型 Ion ...

  2. Python教程百度网盘哪里有?

    Python为我们提供了非常完善的基础代码库,覆盖了网络.文件.GUI.数据库.文本等大量内容,被形象地称作"内置电池(batteries included)".带你快速入门的Py ...

  3. jmeter系列------参数关联

    接口请求中的一个变量需要用上一个接口道服务器返回响应的动态值(上个请求). 遇到这样的情况,我们就需要用到关联 例如用户A发表了一个一条微信朋友圈,用户B想对这条朋友圈进行评论,就需要先获取到这个朋友 ...

  4. HDMI转MIPI DSI芯片方案TC358779XBG

    型号:TC358779XBG功能:HDMI1.4转MIPI DSI通信方式:IIC分辨率:1920*1080电源:3.3/1.8/1.2封装形式:BGA80深圳长期现货 ,提供技术支持,样品申请及规格 ...

  5. spring整合mybatis错误:Caused by: org.xml.sax.SAXParseException; lineNumber: 5; columnNumber: 62; 文档根元素 "mapper" 必须匹配 DOCTYPE 根 "configuration"。

    运行环境:jdk1.7.0_17+tomcat 7 + spring:3.2.0 +mybatis:3.2.7+ eclipse 错误:Caused by: org.xml.sax.SAXParseE ...

  6. oracle数据块核心剖析

    详见: http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp57 数据块(Oracle Data Blocks),本文简称为" ...

  7. Rehat一键安装mysql脚本和备份数据库脚本

    Rehat一键安装mysql脚本 ##说明:适用,Rehat 5 6 7 1.运行状态,运行成功输出mysql临时密码 2.代码如下 #!/bin/bash #获取系统信息 sudo cat /etc ...

  8. Spring MVC 解决无法访问静态文件和"全局异常处理"

    我们都知道,Spring MVC的请求都会去找controller控制器,若果我们页面中引入了一个外部样式,这样是没效果的, 我们引入样式的时候是通过<like href="...&q ...

  9. 对eigrp默认网络的理解!

    EIGRP 默认网络设置的个人总结 (了解即可) //该机制同rip和ospf的default-informationoriginate,原理相同,只是配置格式不同. //!!(唯一作用)该命令起到减 ...

  10. Vue项目搭建基础之Vue-cli模版测试

    第一步安装node,nodejs.org下载node稳定版安装包.node -v   (查看node版本)npm install -g vue-cli(安装Vue脚手架环境)vuevue listvu ...