MyBatis配置文件(四)--typeHandlers
typeHandlers又叫类型处理器,就像在JDBC中,我们在PreparedStatement中设置预编译sql所需的参数或执行sql后根据结果集ResultSet对象获取得到的数据时,需要将数据库中的类型和java中字段的类型进行转换一样,在MyBatis中使用typeHandler来实现。所以说白了,typeHandlers就是用来完成javaType和jdbcType之间的转换。举个比较简单的例子,我创建一个博客表,表中的创建时间和修改时间用VARCHAR类型,但是在我的POJO对象中,创建时间和修改时间的类型是Date,这样我在向数据库插入数据时,需要将日期类型转化成VARCHAR,而从数据库中查询出的结果中,又需要将VARCHAR类型转换成Date.在MyBatis中,使用typeHandlers配置来实现这个转换过程。和别名一样,MyBatis中的类型处理器也存在系统定义的和自定义两种,MyBatis会根据javaType和jdbcType来决定采用哪个typeHandler来处理这些转换规则,而且系统定义的能满足大部分需求,可以说是非常好用,用户只需要自定义一些特有的转换规则,如枚举类型。下面分别介绍这两种typeHandler。
一、系统定义的typeHandler
同上一节的typeAliases,typeHandler也能通过Configuration对象获取到,如下:
- /**
- * 获取类型处理器
- */
- public static void getTypeHandlers() {
- SqlSession sqlSession = getSqlSession();
- TypeHandlerRegistry typeHandlerRegistry = sqlSession.getConfiguration().getTypeHandlerRegistry();
- Collection<TypeHandler<?>> handlers = typeHandlerRegistry.getTypeHandlers();
- System.out.println(handlers.size());
- for (TypeHandler<?> typeHandler : handlers) {
- System.out.println(typeHandler.getClass().getName());
- }
- }
执行结果如下:
- 39
- org.apache.ibatis.type.SqlDateTypeHandler
- org.apache.ibatis.type.ClobReaderTypeHandler
- org.apache.ibatis.type.LocalTimeTypeHandler
- org.apache.ibatis.type.YearMonthTypeHandler
- org.apache.ibatis.type.NStringTypeHandler
- org.apache.ibatis.type.LocalDateTypeHandler
- org.apache.ibatis.type.BigIntegerTypeHandler
- org.apache.ibatis.type.OffsetDateTimeTypeHandler
- org.apache.ibatis.type.ByteObjectArrayTypeHandler
- org.apache.ibatis.type.ArrayTypeHandler
- org.apache.ibatis.type.BigDecimalTypeHandler
- org.apache.ibatis.type.UnknownTypeHandler
- org.apache.ibatis.type.OffsetTimeTypeHandler
- org.apache.ibatis.type.ByteArrayTypeHandler
- org.apache.ibatis.type.DateOnlyTypeHandler
- org.apache.ibatis.type.JapaneseDateTypeHandler
- org.apache.ibatis.type.TimeOnlyTypeHandler
- org.apache.ibatis.type.NClobTypeHandler
- org.apache.ibatis.type.BooleanTypeHandler
- org.apache.ibatis.type.BlobTypeHandler
- org.apache.ibatis.type.YearTypeHandler
- org.apache.ibatis.type.BlobByteObjectArrayTypeHandler
- org.apache.ibatis.type.MonthTypeHandler
- org.apache.ibatis.type.FloatTypeHandler
- org.apache.ibatis.type.DateTypeHandler
- org.apache.ibatis.type.ClobTypeHandler
- org.apache.ibatis.type.BlobInputStreamTypeHandler
- org.apache.ibatis.type.ByteTypeHandler
- org.apache.ibatis.type.SqlTimestampTypeHandler
- org.apache.ibatis.type.ZonedDateTimeTypeHandler
- org.apache.ibatis.type.IntegerTypeHandler
- org.apache.ibatis.type.LocalDateTimeTypeHandler
- org.apache.ibatis.type.CharacterTypeHandler
- org.apache.ibatis.type.SqlTimeTypeHandler org.apache.ibatis.type.DoubleTypeHandler
- org.apache.ibatis.type.ShortTypeHandler
- org.apache.ibatis.type.LongTypeHandler
- 39 org.apache.ibatis.type.InstantTypeHandler
- 40 org.apache.ibatis.type.StringTypeHandler
从结果来看,系统总过定义了39个类型处理器。
现在选择其中的StringTypeHandler来进行分析,看看其源代码
1、获取StringTypeHandler的源代码
- /**
- * Copyright 2009-2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.apache.ibatis.type;
- import java.sql.CallableStatement;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- /**
- * @author Clinton Begin
- */
- public class StringTypeHandler extends BaseTypeHandler<String> {
- @Override
- public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType)
- throws SQLException {
- ps.setString(i, parameter);
- }
- @Override
- public String getNullableResult(ResultSet rs, String columnName)
- throws SQLException {
- return rs.getString(columnName);
- }
- @Override
- public String getNullableResult(ResultSet rs, int columnIndex)
- throws SQLException {
- return rs.getString(columnIndex);
- }
- @Override
- public String getNullableResult(CallableStatement cs, int columnIndex)
- throws SQLException {
- return cs.getString(columnIndex);
- }
- }
从上述代码可以看出它继承了一个叫做BaseTypeHandler<String>的类,这个类的范型是String,即javaType,几个方法如下:
1⃣️setNonNullParameter:这个方法是用来将javaType转换成jdbcTpe
2⃣️getNullableResult:这个方法用来将从结果集根据列名称获取到的数据的jdbcType转换成javaType
3⃣️getNullableResult:这个方法用来将从结果集根据列索引获取到的数据的jdbcType转换成javaType
4⃣️getNullableResult:这个方法用在存储过程中
其实主要就是完成不同类型之间的转换,下面来看一下它所继承的BaseTypeHandler<String>类
2、BaseTypeHandler<String>类源码
- /**
- * Copyright 2009-2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- 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.executor.result.ResultMapException;
- import org.apache.ibatis.session.Configuration;
- /**
- * @author Clinton Begin
- * @author Simone Tripodi
- */
- public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {
- protected Configuration configuration;
- public void setConfiguration(Configuration c) {
- this.configuration = c;
- }
- @Override
- 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 {
- try {
- setNonNullParameter(ps, i, parameter, jdbcType);
- } catch (Exception e) {
- throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
- "Try setting a different JdbcType for this parameter or a different configuration property. " +
- "Cause: " + e, e);
- }
- }
- }
- @Override
- public T getResult(ResultSet rs, String columnName) throws SQLException {
- T result;
- try {
- result = getNullableResult(rs, columnName);
- } catch (Exception e) {
- throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set. Cause: " + e, e);
- }
- if (rs.wasNull()) {
- return null;
- } else {
- return result;
- }
- }
- @Override
- public T getResult(ResultSet rs, int columnIndex) throws SQLException {
- T result;
- try {
- result = getNullableResult(rs, columnIndex);
- } catch (Exception e) {
- throw new ResultMapException("Error attempting to get column #" + columnIndex+ " from result set. Cause: " + e, e);
- }
- if (rs.wasNull()) {
- return null;
- } else {
- return result;
- }
- }
- @Override
- public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
- T result;
- try {
- result = getNullableResult(cs, columnIndex);
- } catch (Exception e) {
- throw new ResultMapException("Error attempting to get column #" + columnIndex+ " from callable statement. Cause: " + e, e);
- }
- 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;
- }
此类是一个抽象类,重写了四个接口之外,还有四个抽象方法,也就是在StringTypeHandler中实现的接口,那么重写的四个接口是什么呢?我们去看一下它所实现的TypeHandler<T>接口
3、接口TypeHandler<T>源代码
- /**
- * Copyright 2009-2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.apache.ibatis.type;
- import java.sql.CallableStatement;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- /**
- * @author Clinton Begin
- */
- public interface TypeHandler<T> {
- void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) 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;
- }
这里也定义了四个接口,一个set方法用来将javaType转为jdbcType,三个get方法用来将jdbcType转为javaType,而在BaseTypeHandler中实现的就是这四个方法。
所以当我们自定义自己的typeHandler时有两种方法:
第一种:继承BaseTypeHandler类
第二种:实现TypeHandler接口
二、自定义typeHandler
我使用实现TypeHandler接口的方式创建一个MyDateHandler,用来完成javaType中的Date类型与jdbcType中的varchar类型之间的转化。
创建MyDateHandler
- package com.daily.handler;
- import java.sql.CallableStatement;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- import org.apache.ibatis.type.DateTypeHandler;
- import org.apache.ibatis.type.JdbcType;
- import org.apache.ibatis.type.TypeHandler;
- import org.postgresql.jdbc2.optional.SimpleDataSource;
- /**
- * 自定义一个TypeHandler用来将javatype的日期类型和jdbctype的VARCHAR进行转换
- */
- public class MyDateHandler implements TypeHandler<Date> {
- @Override
- // 设置sql中指定索引的参数,即将javaType转化为jdbcType
- public void setParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException {
- //设置数据存储到数据库中的格式
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- ps.setString(i, sdf.format(parameter));
- }
- @Override
- // 根据列名称从结果集获取值,并将jdbcType转换成javaType
- public Date getResult(ResultSet rs, String columnName) throws SQLException {
- String columnValue = rs.getString(columnName);
- if (null != columnValue) {
- return new Date(Long.valueOf(columnValue));
- }
- return null;
- }
- @Override
- // 根据列名称从结果集获取值,并将jdbcType转换成javaType
- public Date getResult(ResultSet rs, int columnIndex) throws SQLException {
- String columnValue = rs.getString(columnIndex);
- if (null != columnValue) {
- return new Date(Long.valueOf(columnValue));
- }
- return null;
- }
- @Override
- public Date getResult(CallableStatement cs, int columnIndex) throws SQLException {
- String columnValue = cs.getString(columnIndex);
- if (null != columnValue) {
- return new Date(Long.valueOf(columnValue));
- }
- return null;
- }
- }
下面用一个例子来说明这个handler的使用。
1⃣️创建一个blog表,表中的时间用varchar类型
2⃣️创建POJO对象,将create_time和modify_time的类型定义为Date
- package com.daily.pojo;
- import java.util.Date;
- public class Blog {
- private Integer blogId;
- private String blogTitle;
- private String blogContent;
- private Date createTime;
- private Date modifyTime;
- public Integer getBlogId() {
- return blogId;
- }
- public void setBlogId(Integer blogId) {
- this.blogId = blogId;
- }
- public String getBlogTitle() {
- return blogTitle;
- }
- public void setBlogTitle(String blogTitle) {
- this.blogTitle = blogTitle == null ? null : blogTitle.trim();
- }
- public String getBlogContent() {
- return blogContent;
- }
- public void setBlogContent(String blogContent) {
- this.blogContent = blogContent == null ? null : blogContent.trim();
- }
- public Date getCreateTime() {
- return createTime;
- }
- public void setCreateTime(Date createTime) {
- this.createTime = createTime == null ? null : createTime;
- }
- public Date getModifyTime() {
- return modifyTime;
- }
- public void setModifyTime(Date modifyTime) {
- this.modifyTime = modifyTime == null ? null : modifyTime;
- }
- }
3⃣️在mybatis-config.xml文件中注册刚才自定义的MyDateHandler
- <!--类型处理器 -->
- <typeHandlers>
- <!-- 注册自定义handler,说明它作用的jdbcType和javaType -->
- <typeHandler jdbcType="VARCHAR" javaType="date" handler="com.daily.handler.MyDateHandler" />
- </typeHandlers>
4⃣️在BlogMapper.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="com.daily.dao.BlogMapper">
- <resultMap id="BaseResultMap" type="com.daily.pojo.Blog">
- <id column="blog_id" jdbcType="INTEGER" property="blogId" />
- <result column="blog_title" jdbcType="VARCHAR" property="blogTitle" />
- <result column="blog_content" jdbcType="VARCHAR" property="blogContent" />
- <!-- 不使用MyDateHandler-->
- <result column="create_time" jdbcType="VARCHAR" property="createTime" />
- <!-- 使用MyDateHandler-->
- <result column="modify_time" typeHandler="com.daily.handler.MyDateHandler" property="modifyTime" />
- </resultMap>
- <insert id="insert" parameterType="com.daily.pojo.Blog">
- insert into blog (blog_id, blog_title, blog_content,
- create_time, modify_time)
- values (#{blogId,jdbcType=INTEGER}, #{blogTitle,jdbcType=VARCHAR},
- #{blogContent,jdbcType=VARCHAR},
- #{createTime,jdbcType=VARCHAR}, #{modifyTime,typeHandler=com.daily.handler.MyDateHandler})
- </insert>
- </mapper>
5⃣️查看结果
第一种:create_time不设置typeHandler,modify_time设置typeHandler
从上面的结果来看,虽然create_time没有设置typeHandler,但是结果跟使用了typeHandler的modify_time是一样的,那么我把两个都去掉呢?
第二种:两个都不设置
可以看到结果也是一样,下面我去掉注册的MyDateHandler呢?
第三种:去掉MyDateHandler
从上述结果可以看到,当去掉自定义的处理器时,MyBatis会根据结果自动选择合适的handler进行转换。
日常开发中,一般不需要定义,使用默认的就可以,除非是像枚举这种特殊类型就需要自己实现。
以上就是MyBatis配置文件中typeHandlers的配置内容。
MyBatis配置文件(四)--typeHandlers的更多相关文章
- MyBatis学习(四)、MyBatis配置文件
四.MyBatis主配置文件 在定义sqlSessionFactory时需要指定MyBatis主配置文件: <bean id="sqlSessionFactory" clas ...
- MyBatis学习 之 四、MyBatis配置文件
目录(?)[-] 四MyBatis主配置文件 properties属性 settings设置 typeAliases类型别名 typeHandlers类型句柄 ObjectFactory对象工厂 pl ...
- Mybatis系列全解(四):全网最全!Mybatis配置文件XML全貌详解
封面:洛小汐 作者:潘潘 做大事和做小事的难度是一样的.两者都会消耗你的时间和精力,所以如果决心做事,就要做大事,要确保你的梦想值得追求,未来的收获可以配得上你的努力. 前言 上一篇文章 <My ...
- 详解mybatis配置文件
在前面两篇文章中,大致与大家分享了基于Java的ORM框架,Mybatis基本架构和Mybatis实现CRUD的基本原理与流程,在本篇文章中,继续与大家分享Mybatis配置文件. 通过研究Mybat ...
- Mybatis配置文件
XML 映射配置文件 MyBatis 的配置文件包含了设置(settings)和属性(properties)信息. properties 这些属性都是可外部配置且可动态替换的,既可以在典型的 Java ...
- MyBatis配置文件解析
MyBatis配置文件解析(概要) 1.configuration:根元素 1.1 properties:定义配置外在化 1.2 settings:一些全局性的配置 1.3 typeAliases:为 ...
- 02.MyBatis配置文件详解
MyBatis入参考文档:http://mybatis.org/mybatis-3/zh/ 1.properties 属性 1.在MyBatis配置文件中引用属性文件 MyBatis ...
- Mybatis(一):MyBatis配置文件config.xml详解
MyBatis 配置文件基本结构 在使用mybatis框架时,首先导入其对应的jar包,并进行相应的配置,所以得对配置文件的每个参数都得了解.一个完全的mybatis配置文件结构如下: <?xm ...
- mybatis 学习四 源码分析 mybatis如何执行的一条sql
总体三部分,创建sessionfactory,创建session,执行sql获取结果 1,创建sessionfactory 这里其实主要做的事情就是将xml的所有配置信息转换成一个Confi ...
随机推荐
- 在任务管理中显示进程ID号
- 次短路 /// dijkstra oj1597
题目大意: 给出一个有向图,求从 顶点a 到 顶点b 的次短路. 第一行是2个正整数 n 和 e,表示该有向图的顶点数和边数.3 < n ≤ 5000 , 3 < e < 40000 ...
- Activiti学习笔记2 — HelloWorld
一. Maven的POM配置文件 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="htt ...
- kali linux 入门(1) 基于win10和docker的环境搭建
1. 前言 渗透测试并没有一个标准的定义.国外一些安全组织达成共识的通用说法是,渗透测试是通过模拟恶意黑客的攻击方法,来评估计算机网络系统安全的一种评估方法,这个过程包括对系统的任何弱点.技术缺陷或漏 ...
- Nginx的安装--------tar包安装
Nginx的安装,在网上搜索是很多的结果,但是 真的安装起来却花费了不少 心思,总结起来就是依赖包安装了,但是没有指定对的路径,在安装的过程中遇到过两个问题: ①make[1]: *** [/usr/ ...
- 实现Linux下不间断聊天和退出处理
实现Linux下不间断聊天和退出处理
- CF1163E Magical Permutation
题意:给定集合,求一个最大的x,使得存在一个0 ~ 2x - 1的排列,满足每相邻的两个数的异或值都在S中出现过.Si <= 2e5 解:若有a,b,c,令S1 = a ^ b, S2 = b ...
- csps模拟68d,e,f题解
题面:https://www.cnblogs.com/Juve/articles/11655531.html 三道数据结构? d: 贪心,先按a排序,然后枚举删了前i个a值比较小的,然后在剩下的里面删 ...
- ng-zorro-mobile中遇到的问题
一.Modal(弹出框)使用上的问题 在官方文档中,Modal是这样使用的: 这里需要注意的一点就是,看到上方代码中只用了Modal的全局方式,所以个人认为下面这段注入初始化的东西是没有用的便去掉: ...
- vue 自定义指令input表单的数据验证
一.代码 <template> <div class="check" > <h3>{{msg}}</h3> <div clas ...