spring+mybatis中typehandler怎么配置

  • Post author:
  • Post category:其他


我们在不使用spring来管理的时候通常把typehandler的配置放到mybatis-config.xml中,如下:

<configuration>
    <typeHandlers>
      <!-- 
          当配置package的时候,mybatis会去配置的package扫描TypeHandler
          <package name="com.dy.demo"/>
       -->

      <!-- handler属性直接配置我们要指定的TypeHandler -->
      <typeHandler handler=""/>

      <!-- javaType 配置java类型,例如String, 如果配上javaType, 那么指定的typeHandler就只作用于指定的类型 -->
      <typeHandler javaType="" handler=""/>

      <!-- jdbcType 配置数据库基本数据类型,例如varchar, 如果配上jdbcType, 那么指定的typeHandler就只作用于指定的类型  -->
      <typeHandler jdbcType="" handler=""/>

      <!-- 也可两者都配置 -->
      <typeHandler javaType="" jdbcType="" handler=""/>

  </typeHandlers>

  ......

</configuration>

但是对于我们现在的开发环境来说,spring太流行了,所以这里就成了一块问题。

闲话不多说,直接上spring的配置:

    <!--声明TypeHandler bean-->
    <bean id="myStringTypeHandler" class="util.MyStringTypeHandler"/>

    <!-- 创建spring工厂 -->
    <bean id="ssf" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--data source的配置不变-->
        <property name="dataSource" ref="ds"/>
        <!--实体类别名-->
        <property name="typeAliasesPackage" value="model"/>
        <!--mapper文件注入-->
        <property name="mapperLocations" value="classpath:/mybatis-mapper/*/*DaoImpl.xml"/>
        <!--typeHandler注入-->
        <property name="typeHandlers" ref="myStringTypeHandler"/>
    </bean>

下面简单的介绍下typehandler的配置吧。

首先是官方对于这个属性的介绍:

页一

页二

以下是mybatis中转化string的源码:

package org.apache.ibatis.type;

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

public class StringTypeHandler extends BaseTypeHandler<String> {
    public StringTypeHandler() {
    }

    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, parameter);
    }

    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return rs.getString(columnName);
    }

    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return rs.getString(columnIndex);
    }

    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return cs.getString(columnIndex);
    }
}

BaseTypeHandler源码:

package org.apache.ibatis.type;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.session.Configuration;

public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {
    protected Configuration configuration;

    public BaseTypeHandler() {
    }

    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 var6) {
                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: " + var6, var6);
            }
        } else {
            this.setNonNullParameter(ps, i, parameter, jdbcType);
        }

    }

    public T getResult(ResultSet rs, String columnName) throws SQLException {
        T result = this.getNullableResult(rs, columnName);
        return rs.wasNull()?null:result;
    }

    public T getResult(ResultSet rs, int columnIndex) throws SQLException {
        T result = this.getNullableResult(rs, columnIndex);
        return rs.wasNull()?null:result;
    }

    public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
        T result = this.getNullableResult(cs, columnIndex);
        return cs.wasNull()?null:result;
    }

    public abstract void setNonNullParameter(PreparedStatement var1, int var2, T var3, JdbcType var4) throws SQLException;

    public abstract T getNullableResult(ResultSet var1, String var2) throws SQLException;

    public abstract T getNullableResult(ResultSet var1, int var2) throws SQLException;

    public abstract T getNullableResult(CallableStatement var1, int var2) throws SQLException;
}

经过查看我们发现只需要实现BaseTypeHandler这个抽象类即可,记得泛型一定是String。

以下是我自己的代码,其中oracle数据库编码为ISO-8859-1,项目编码为GBK:

package util;

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

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

/**
 * 转化String的result与parameter
 * 注意:实现BaseTypeHandler时,泛型必须为String
 */
public class MyStringTypeHandler extends BaseTypeHandler<String> {
    private static final Logger log = Logger.getLogger(MyStringTypeHandler.class);

    /**
     * 转化字符串编码
     * @param str
     * @param oldCharset
     * @param newCharset
     * @return
     */
    private static String convertEncoding(String str,String oldCharset,String newCharset){
        String resultStr = null;
        try{
            if (str == null) {
                return resultStr;
            }
            resultStr = new String(str.getBytes(oldCharset),newCharset);
        }catch(UnsupportedEncodingException e){
            log.error(e.getMessage(),e);
        }
        return resultStr;
    }

    public MyStringTypeHandler() {
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int index, String parameter, JdbcType jdbcType) throws SQLException {
        parameter = convertEncoding(parameter, "GBK","ISO-8859-1");
        ps.setString(index,parameter);
    }

    @Override
    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return convertEncoding(rs.getString(columnName),"ISO-8859-1","GBK");
    }

    @Override
    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return convertEncoding(rs.getString(columnIndex),"ISO-8859-1","GBK");
    }

    @Override
    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return convertEncoding(cs.getString(columnIndex),"ISO-8859-1","GBK");
    }
}

补充:以上可以解决正常的需求,但是大多码农都是不正常的,最近又遇到一个问题,也在这里加上。

当我们插入数据的时候,有些数据是可以为空的,MyBatis支持我们这样写:

<!--一个简单的插入语句-->
<insert id="insertUser">
        insert into user
            (id,username,password,address)
        values
            (#{id},
            #{username}
            #{password},
            #{address,jdbcType=VARCHAR})
    </insert>

这就会产生问题了,在我们加上了jdbcType=xxx这个配置后,MyBatis不再访问我们的TypeHandler,之后经过百度,发现可以使用如下几种方式解决:

<!--配置resultMap-->
<resultMap id="userResultMap" type="User">
        <result typeHandler="StringTypeHandler" column="address" javaType="java.lang.String"
                jdbcType="VARCHAR"
                property="address"/>
    </resultMap>
<!--调用-->
<select id="getUser" resultMap="userResultMap">
        select * from user
</select>
<!--这个方法的缺点在于配置比较繁琐,返回时配置resultMap,插入时配置parameterMap,还要设置每个对象的每一个属性-->
<!--这个方法简洁了很多,但是你想想我们有一个20多个字段的表,好吧,画面太美不敢想-->
<insert id="insertUser" parameterType="User">
        INSERT INTO user(username,password,address) VALUES (#{username},#{password},#{address,javaType=String,jdbcType=VARCHAR,typeHandler=StringTypeHandler(这里注意要写类全名的)})
    </insert>

我推荐下面这个方法,经过注解配置,数据库类型为xxx的,java类型为xxx的,都会经过这个转换类,果然注解才是好东西哇~

另外,你注意到注解中的值被用大括号括起来了么,这说明注解值可以是一个数组,就像我们这个字符转码类,

还能这样:@MapperJdbcTypes({JdbcType.VARCHAR,JdbcType.CHAR})

和这样:@MappedTypes({String.class,Character.class})

当然,我只是举个栗子,还是要看需求的

import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
//这个注解定义的是JdbcType类型,这里的类型不可自己随意定义,必须要是枚举类org.apache.ibatis.type.JdbcType所枚举的数据类型
@MappedJdbcTypes({JdbcType.VARCHAR})
//这里定义的是JavaType的数据类型,描述了哪些Java类型可被拦截
@MappedTypes({String.class})
public class StringTypeHandler extends BaseTypeHandler<String> {...}

学习知识要晓出处,以上的配置jdbcType方法学习自

http://blog.csdn.net/u012702547/article/details/54572679

如果有不对的地方,还请大神在下面评论区指导。当然,如果这些代码有什么疑问,也可以在下方留言。



版权声明:本文为zhaoyf7746原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。