mybatis TypeHandler详解
来源:互联网 发布:itc智能网络广播 编辑:程序博客网 时间:2024/06/11 22:28
1.TypeHandler概念
TypeHandler,类型转换器,在mybatis中用于实现java类型和JDBC类型的相互转换.mybatis使用prepareStatement来进行参数设置的时候,需要通过typeHandler将传入的java参数设置成合适的jdbc类型参数,这个过程实际上是通过调用PrepareStatement不同的set方法实现的;在获取结果返回之后,也需要将返回的结果转换成我们需要的java类型,这时候是通过调用ResultSet对象不同类型的get方法时间的;所以不同类型的typeHandler其实就是调用PrepareStatement和ResultSet的不同方法来进行类型的转换,有些时候会在调用PrepareStatement和ResultSet的相关方法之前,可以对传入的参数进行一定的处理.
当我们没有指定typeHandler的时候mybatis会根据传入参数的类型和返回值的类型调用默认的typeHandler进行处理.对于一个typeHandler需要配置java类型(javaType)和JDBC类型(jdbcType),typeHandler的作用就是实现这两种类型的转换,在传入的参数为指定的Java类型时,将其转换为指定的JDBC类型,当返回值为指定JDBC类型时将其转换为配置的Java类型.
2.mybatis默认定义的TypeHandler
mybatis默认定义了一批TypeHandler,正常情况下这些TypeHandler就可以满足我们的使用了.mybatis通过TypeHandlerRegister来管理TypeHandler
所以在这个类里面可以看到所有定义好的typeHandler,下面是源码.
private final Map<JdbcType, TypeHandler<?>> JDBC_TYPE_HANDLER_MAP = new EnumMap<JdbcType, TypeHandler<?>>(JdbcType.class); private final Map<Type, Map<JdbcType, TypeHandler<?>>> TYPE_HANDLER_MAP = new ConcurrentHashMap<Type, Map<JdbcType, TypeHandler<?>>>(); private final TypeHandler<Object> UNKNOWN_TYPE_HANDLER = new UnknownTypeHandler(this); private final Map<Class<?>, TypeHandler<?>> ALL_TYPE_HANDLERS_MAP = new HashMap<Class<?>, TypeHandler<?>>(); private static final Map<JdbcType, TypeHandler<?>> NULL_TYPE_HANDLER_MAP = new HashMap<JdbcType, TypeHandler<?>>(); public TypeHandlerRegistry() { register(Boolean.class, new BooleanTypeHandler()); register(boolean.class, new BooleanTypeHandler()); register(JdbcType.BOOLEAN, new BooleanTypeHandler()); register(JdbcType.BIT, new BooleanTypeHandler()); register(Byte.class, new ByteTypeHandler()); register(byte.class, new ByteTypeHandler()); register(JdbcType.TINYINT, new ByteTypeHandler()); register(Short.class, new ShortTypeHandler()); register(short.class, new ShortTypeHandler()); register(JdbcType.SMALLINT, new ShortTypeHandler()); register(Integer.class, new IntegerTypeHandler()); register(int.class, new IntegerTypeHandler()); register(JdbcType.INTEGER, new IntegerTypeHandler()); register(Long.class, new LongTypeHandler()); register(long.class, new LongTypeHandler()); register(Float.class, new FloatTypeHandler()); register(float.class, new FloatTypeHandler()); register(JdbcType.FLOAT, new FloatTypeHandler()); register(Double.class, new DoubleTypeHandler()); register(double.class, new DoubleTypeHandler()); register(JdbcType.DOUBLE, new DoubleTypeHandler()); register(Reader.class, new ClobReaderTypeHandler()); register(String.class, new StringTypeHandler()); register(String.class, JdbcType.CHAR, new StringTypeHandler()); register(String.class, JdbcType.CLOB, new ClobTypeHandler()); register(String.class, JdbcType.VARCHAR, new StringTypeHandler()); register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler()); register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler()); register(String.class, JdbcType.NCHAR, new NStringTypeHandler()); register(String.class, JdbcType.NCLOB, new NClobTypeHandler()); register(JdbcType.CHAR, new StringTypeHandler()); register(JdbcType.VARCHAR, new StringTypeHandler()); register(JdbcType.CLOB, new ClobTypeHandler()); register(JdbcType.LONGVARCHAR, new ClobTypeHandler()); register(JdbcType.NVARCHAR, new NStringTypeHandler()); register(JdbcType.NCHAR, new NStringTypeHandler()); register(JdbcType.NCLOB, new NClobTypeHandler()); register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler()); register(JdbcType.ARRAY, new ArrayTypeHandler()); register(BigInteger.class, new BigIntegerTypeHandler()); register(JdbcType.BIGINT, new LongTypeHandler()); register(BigDecimal.class, new BigDecimalTypeHandler()); register(JdbcType.REAL, new BigDecimalTypeHandler()); register(JdbcType.DECIMAL, new BigDecimalTypeHandler()); register(JdbcType.NUMERIC, new BigDecimalTypeHandler()); register(InputStream.class, new BlobInputStreamTypeHandler()); register(Byte[].class, new ByteObjectArrayTypeHandler()); register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler()); register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler()); register(byte[].class, new ByteArrayTypeHandler()); register(byte[].class, JdbcType.BLOB, new BlobTypeHandler()); register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler()); register(JdbcType.LONGVARBINARY, new BlobTypeHandler()); register(JdbcType.BLOB, new BlobTypeHandler()); register(Object.class, UNKNOWN_TYPE_HANDLER); register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER); register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER); register(Date.class, new DateTypeHandler()); register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler()); register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler()); register(JdbcType.TIMESTAMP, new DateTypeHandler()); register(JdbcType.DATE, new DateOnlyTypeHandler()); register(JdbcType.TIME, new TimeOnlyTypeHandler()); register(java.sql.Date.class, new SqlDateTypeHandler()); register(java.sql.Time.class, new SqlTimeTypeHandler()); register(java.sql.Timestamp.class, new SqlTimestampTypeHandler()); // mybatis-typehandlers-jsr310 try { // since 1.0.0 register("java.time.Instant", "org.apache.ibatis.type.InstantTypeHandler"); register("java.time.LocalDateTime", "org.apache.ibatis.type.LocalDateTimeTypeHandler"); register("java.time.LocalDate", "org.apache.ibatis.type.LocalDateTypeHandler"); register("java.time.LocalTime", "org.apache.ibatis.type.LocalTimeTypeHandler"); register("java.time.OffsetDateTime", "org.apache.ibatis.type.OffsetDateTimeTypeHandler"); register("java.time.OffsetTime", "org.apache.ibatis.type.OffsetTimeTypeHandler"); register("java.time.ZonedDateTime", "org.apache.ibatis.type.ZonedDateTimeTypeHandler"); // since 1.0.1 register("java.time.Month", "org.apache.ibatis.type.MonthTypeHandler"); register("java.time.Year", "org.apache.ibatis.type.YearTypeHandler"); // since 1.0.2 register("java.time.YearMonth", "org.apache.ibatis.type.YearMonthTypeHandler"); register("java.time.chrono.JapaneseDate", "org.apache.ibatis.type.JapaneseDateTypeHandler"); } catch (ClassNotFoundException e) { // no JSR-310 handlers } // issue #273 register(Character.class, new CharacterTypeHandler()); register(char.class, new CharacterTypeHandler()); }
可以看到对于一个Java类型是可以有多个JDBC类型相对应的,所以会存在多个TypeHandler,在这种情况下需要根据传入参数的javaType以及其在数据库中对应JdbcType一起来选定一个TypeHandler进行处理(mybatis如何知道每个字段对应的数据库字段类型的?).下面来看一个具体的TypeHandler的实现:实现Java中Date类型和jdbc中JdbcType.Time类型转换的TimeOnlyTypeHandler.JDBC中的Time类型只记录时分秒,所以如果我们传入一个代表2017-11-21 11:55:59的Date对象,那么数据库中存储的时间是11:55:59.下面看下具体的源码实现:
package org.apache.ibatis.type;import java.sql.CallableStatement;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Time;import java.util.Date;/** * @author Clinton Begin */public class TimeOnlyTypeHandler extends BaseTypeHandler<Date> { @Override public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException { ps.setTime(i, new Time(parameter.getTime())); } @Override public Date getNullableResult(ResultSet rs, String columnName) throws SQLException { java.sql.Time sqlTime = rs.getTime(columnName); if (sqlTime != null) { return new Date(sqlTime.getTime()); } return null; } @Override public Date getNullableResult(ResultSet rs, int columnIndex) throws SQLException { java.sql.Time sqlTime = rs.getTime(columnIndex); if (sqlTime != null) { return new Date(sqlTime.getTime()); } return null; } @Override public Date getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { java.sql.Time sqlTime = cs.getTime(columnIndex); if (sqlTime != null) { return new Date(sqlTime.getTime()); } return null; }}
3.使用自定义TypeHandler
虽然大部分时候mybatis提供的typeHandler已经够用了,但总有些情况下需要我们自己定义TypeHandler.下面通过一个实例来研究如何自己定义和使用TypeHandler.
现在的场景是:首先是建立了一个person表存储个人信息,这个表里有一栏hobbys是记录个人爱好的,爱好包括足球,排球,游泳之类的,在Java的Person对象中对应的是一个String类型的list,而在数据库中是以逗号分隔的字符串表示的,心事如”足球,排球,游泳”,所以现在需要定义一个TypeHandler实现在插入数据和查询数据时string和list类型的相互转换.自定义一个TypeHandler需要继承TypeHandler T接口,T是传入的java类型,并需要使用@MappedTypes定义需要被拦截的java类型@MappedJdbcTypes配置jdbc类型,这里的JdbcType必须org.apache.ibatis.type.JdbcType中的枚举类型,然后还需要实现TypeHandler接口中一系列的get set方法,具体实现的代码如下:
package com.sankuai.lkl.typeHandler;import com.sun.deploy.util.StringUtils;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 java.sql.CallableStatement;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.Arrays;import java.util.List;@MappedJdbcTypes(JdbcType.VARCHAR)@MappedTypes({List.class})public class ListTypeHandler implements TypeHandler<List<String>> { @Override public void setParameter(PreparedStatement ps, int i, List<String> parameter, JdbcType jdbcType) throws SQLException { String hobbys = StringUtils.join(parameter, ","); try { ps.setString(i, hobbys); } catch (Exception e) { e.printStackTrace(); } } @Override public List<String> getResult(CallableStatement cs, int columnIndex) throws SQLException { String hobbys = cs.getString(columnIndex); return Arrays.asList(hobbys.split(",")); } @Override public List<String> getResult(ResultSet rs, int columnIndex) throws SQLException { return Arrays.asList(rs.getString(columnIndex).split(",")); } @Override public List<String> getResult(ResultSet rs, String columnName) throws SQLException { return Arrays.asList(rs.getString(columnName).split(",")); }}
自定义完成之后就需要在mybatis-config.xml文件中配置以注册到mybatis中
<typeHandlers> <typeHandler jdbcType="VARCHAR" javaType="list" handler="com.sankuai.lkl.typeHandler.ListTypeHandler"/></typeHandlers>
但注册完成之后也仍然不能起作用,因为还需要标识那些参数和返回的结果是需要使用这个TypeHandler进行处理的;具体来说,在插入数据和对返回结果进行处理的时候,可以对参数配置javaType和jdbcType或直接配置typeHandler属性来进行标识
下面是插入数据时标识用指定TypeHandler进行处理
<insert id="insertPerson" parameterType="person"> INSERT INTO person (id,name,sex,hobbys,data_time) values(#{id},#{name},#{sex},#{hobbys,typeHandler=com.sankuai.lkl.typeHandler.ListTypeHandler},#{date})</insert>
下面是标识对返回的结果用指定TypeHandler进行处理
<resultMap id="personMap" type="person"> <id property="id" column="id"/> <result property="name" column="name"/> <result property="sex" column="sex"/> <result property="hobbys" column="hobbys" typeHandler="com.sankuai.lkl.typeHandler.ListTypeHandler"/> <result property="date" column="data_time"/> </resultMap>
这样进行配置之后就可以使用自定义的TypeHandler处理javaType和JdbcType的转换了.
- mybatis TypeHandler详解
- mybatis typeHandler
- Mybatis TypeHandler
- mybatis typeHandler
- MyBatis TypeHandler
- Mybatis 示例之 TypeHandler
- Mybatis自定义typehandler
- MyBatis-自定义typeHandler
- MyBatis之typeHandler
- Mybatis 自定义 TypeHandler
- Mybatis自定义TypeHandler
- Mybatis中的TypeHandler介绍
- Mybatis TypeHandler的使用
- MyBatis之TypeHandler解析
- mybatis typeHandler自定义类型转换器
- mybatis typeHandler自定义类型转换器
- Mybatis中typeHandler的使用
- Mybatis类型转换TypeHandler介绍
- 【SpringMVC】配置逻辑视图名
- Ubuntu解决sudo: source: command not found错误
- 小波变换教程(十一)
- POJ——Problem1088(滑雪,动态规划)
- Ionic3学习笔记(九)关于 Android 端软键盘弹出后界面被压缩的问题
- mybatis TypeHandler详解
- Wireshark 的使用 —— 过滤器(filter)
- openAI gym5
- 今日小结
- 5.3.3 日期/时间组件方法
- Apache的虚拟主机、内部访问控制及支持语言
- linux系统如何安装adobe flash player
- 水仙花数
- ELK