spring boot mybatis TypeHandler 看源码如何初始化及调用

目录

  • 概述
  • 使用
    • TypeHandler
    • 使用方式
      • 在 select | update | insert 中加入
    • 配置文件中指定
  • 源码分析
    • 配置文件指定
    • Mapper
  • 执行query
    • 如何转换
  • 结束

概述

阅读此文 可以达到 spring boot mybatis TypeHandler 源码如何初始化及如何调用的。

spring boot 版本为 2.7.17,mybatis(spring boot) 2.3.2
TypeHandler 是 mybatis 中 java 对象和数据库 jdbc 之间进行类型转换的桥梁。

调用层级深,比较复杂,关键源码点,给出了详细的位置,打上断点,降低难度。

接口源码如下:

public interface TypeHandler<T> {// 从java对象到数据库类型的转换void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;// 下面三个是从数据库到java对象的转换T getResult(ResultSet rs, String columnName) throws SQLException;T getResult(ResultSet rs, int columnIndex) throws SQLException;T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}

使用

TypeHandler

实现 TypeHandler 接口,也可以实现抽象类 BaseTypeHandler

代码如下:

@MappedJdbcTypes(JdbcType.VARCHAR)
@MappedTypes(Reason.class)
public class ResonJsonTypeHandler extends BaseTypeHandler<Reason> {@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, Reason parameter, JdbcType jdbcType) throws SQLException {// 将java对象转换成jdbc中的类型ps.setString(i, JSON.toJSONString(parameter));}@Overridepublic Reason getNullableResult(ResultSet rs, String columnName) throws SQLException {return JSON.parseObject(rs.getString(columnName), Reason.class);}@Overridepublic Reason getNullableResult(ResultSet rs, int columnIndex) throws SQLException {return JSON.parseObject(rs.getString(columnIndex), Reason.class);}@Overridepublic Reason getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {return JSON.parseObject(cs.getString(columnIndex), Reason.class);}
}

注意:

  • @MappedJdbcTypes 代表对应的数据库中字段的类型,json本质上也是字符串
  • @MappedTypes 代表要转换的 JavaBean 对象
  • java对象与json格式的互相转换需要 JSON 来完成

使用方式

在 select | update | insert 中加入

写在 xml 只有对应的 sql 会被转换
在这里插入图片描述

org.apache.ibatis.mapping.ResultMapping.Builder#resolveTypeHandler

配置文件中指定

如下配置,任何使用 Reason 的地方都会进行转换。

mybatis:type-handlers-package: com.fun.demo.mybatis.type.handler

由于 xmlmapper 都是会生成覆盖,所以选择配置文件中指定。

源码分析

配置文件指定

protected SqlSessionFactory buildSqlSessionFactory() throws Exception {final Configuration targetConfiguration;XMLConfigBuilder xmlConfigBuilder = null;
....if (hasLength(this.typeHandlersPackage)) {scanClasses(this.typeHandlersPackage, TypeHandler.class).stream().filter(clazz -> !clazz.isAnonymousClass()).filter(clazz -> !clazz.isInterface()).filter(clazz -> !Modifier.isAbstract(clazz.getModifiers())).forEach(targetConfiguration.getTypeHandlerRegistry()::register);}if (!isEmpty(this.typeHandlers)) {Stream.of(this.typeHandlers).forEach(typeHandler -> {targetConfiguration.getTypeHandlerRegistry().register(typeHandler);LOGGER.debug(() -> "Registered type handler: '" + typeHandler + "'");});}....

scanClasses 方法进行加载自定义的 typeHandler
org.mybatis.spring.SqlSessionFactoryBean#scanClasses
在这里插入图片描述
org.apache.ibatis.mapping.ResultMapping.Builder#resolveTypeHandler
在这里插入图片描述

Mapper

在 Mapper 中自定义时,依然也是在 SqlSessionFactoryBean 的 buildSqlSessionFactory 方法。

org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration#sqlSessionFactory
org.mybatis.spring.SqlSessionFactoryBean#afterPropertiesSet
org.apache.ibatis.builder.xml.XMLMapperBuilder#parse
org.apache.ibatis.builder.xml.XMLMapperBuilder#configurationElement
org.apache.ibatis.builder.xml.XMLMapperBuilder#resultMapElements
org.apache.ibatis.builder.xml.XMLMapperBuilder#resultMapElement(org.apache.ibatis.parsing.XNode)
org.apache.ibatis.builder.xml.XMLMapperBuilder#resultMapElement(org.apache.ibatis.parsing.XNode, java.util.List<org.apache.ibatis.mapping.ResultMapping>, java.lang.Class<?>)
org.apache.ibatis.builder.MapperBuilderAssistant#buildResultMapping(java.lang.Class<?>, java.lang.String, java.lang.String, java.lang.Class<?>, org.apache.ibatis.type.JdbcType, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Class<? extends org.apache.ibatis.type.TypeHandler<?>>, java.util.List<org.apache.ibatis.mapping.ResultFlag>, java.lang.String, java.lang.String, boolean)
org.apache.ibatis.builder.BaseBuilder#resolveTypeHandler(java.lang.Class<?>, java.lang.Class<? extends org.apache.ibatis.type.TypeHandler<?>>)
public void parse() {if (!configuration.isResourceLoaded(resource)) {configurationElement(parser.evalNode("/mapper"));configuration.addLoadedResource(resource);bindMapperForNamespace();}parsePendingResultMaps();parsePendingCacheRefs();parsePendingStatements();
}

具体的解析 /mapper 元素

private void configurationElement(XNode context) {try {String namespace = context.getStringAttribute("namespace");if (namespace == null || namespace.isEmpty()) {throw new BuilderException("Mapper's namespace cannot be empty");}builderAssistant.setCurrentNamespace(namespace);cacheRefElement(context.evalNode("cache-ref"));cacheElement(context.evalNode("cache"));parameterMapElement(context.evalNodes("/mapper/parameterMap"));resultMapElements(context.evalNodes("/mapper/resultMap"));sqlElement(context.evalNodes("/mapper/sql"));buildStatementFromContext(context.evalNodes("select|insert|update|delete"));} catch (Exception e) {throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);}
}
  private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings,Class<?> enclosingType) {
.......List<XNode> resultChildren = resultMapNode.getChildren();for (XNode resultChild : resultChildren) {if ("constructor".equals(resultChild.getName())) {processConstructorElement(resultChild, typeClass, resultMappings);} else if ("discriminator".equals(resultChild.getName())) {discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);} else {List<ResultFlag> flags = new ArrayList<>();if ("id".equals(resultChild.getName())) {flags.add(ResultFlag.ID);}resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));}}
.....}

在这里插入图片描述

buildResultMappingFromContext

 private ResultMapping buildResultMappingFromContext(XNode context, Class<?> resultType, List<ResultFlag> flags) {String property;if (flags.contains(ResultFlag.CONSTRUCTOR)) {property = context.getStringAttribute("name");} else {property = context.getStringAttribute("property");}......String nestedResultMap = context.getStringAttribute("resultMap",() -> processNestedResultMappings(context, Collections.emptyList(), resultType));....String typeHandler = context.getStringAttribute("typeHandler");String resultSet = context.getStringAttribute("resultSet");String foreignColumn = context.getStringAttribute("foreignColumn");.....}

String typeHandler = context.getStringAttribute(“typeHandler”);

执行query

如何转换

org.apache.ibatis.executor.SimpleExecutor#doQuery
在这里插入图片描述

org.apache.ibatis.session.Configuration#newStatementHandler
org.apache.ibatis.executor.statement.RoutingStatementHandler#RoutingStatementHandler
org.apache.ibatis.executor.statement.PreparedStatementHandler
org.apache.ibatis.executor.statement.BaseStatementHandler#BaseStatementHandler
org.apache.ibatis.executor.statement.RoutingStatementHandler#query
org.apache.ibatis.logging.jdbc.PreparedStatementLogger#invoke
org.apache.ibatis.executor.resultset.ResultSetHandler#handleResultSets
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSet
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleRowValues
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleRowValuesForSimpleResultMap
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#applyPropertyMappings
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#getPropertyMappingValue
com.fun.demo.mybatis.type.handler.ResonJsonTypeHandler#getNullableResult(java.sql.ResultSet, java.lang.String)

在这里插入图片描述
执行结果
在这里插入图片描述

结束

spring boot mybatis TypeHandler 如何初始化及如何调用,就解释的非常明白了,如有疑问,欢迎评论区留言。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/189448.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL Server 2016(创建数据表)

1、需求描述。 在名为“class”的数据库中创建表&#xff0c;表名称为“course”&#xff0c;其中要包含序号、课程、课程编号、学分、任课教师、上课地点、开始时间、结束时间、备注等列。 设置各个字段的数据类型。其中&#xff0c;"序号"列为标识列&#xff0c;从…

分享几个可以免费使用GPT工具

1. 国产可以使用GPT3.5和4.0的网站&#xff0c;每日有免费的使用额度&#xff0c;响应速度&#xff0c;注册时不用使用手机号&#xff0c;等个人信息&#xff0c;注重用户隐私&#xff0c;好评&#xff01; 一个好用的ChatGPT系统 &#xff0c;可以免费使用3.5 和 4.0https://…

企业如何做好合规管理?

近年来“合规”作为一个热点话题&#xff0c;频繁出现在公众视野&#xff0c;已然成为企业管理发展的大趋势。国家相继出台的各项合规管理标准预示着我国的企业合规管理正逐步从头部央企向民营企业扩展。因此&#xff0c;各大企业将合规管理作为了企业管理的首要任务。 随着中…

Mysql 行转列,把逗号分隔的字段拆分成多行

目录 效果如下源数据变更后的数据 方法第一种示例SQL和业务结合在一起使用 第二种示例SQL和业务结合在一起使用 结论 效果如下 源数据 变更后的数据 方法 第一种 先执行下面的SQL&#xff0c;看不看能不能执行&#xff0c;如果有结果&#xff0c;代表数据库版本是可以的&…

C语言:写一个函数,输入一个十六进制数,输出相应的十进制数

分析&#xff1a; 当用户运行该程序时&#xff0c;程序会提示用户输入一个十六进制数。用户需要在命令行中输入一个有效的十六进制数&#xff0c;例如&#xff1a;"1A3F"。 接下来&#xff0c;程序调用了名为 xbed 的函数&#xff0c;并将用户输入的十六进制数作…

激光SLAM:Faster-Lio 算法编译与测试

激光SLAM&#xff1a;Faster-Lio 算法编译与测试 前言编译测试离线测试在线测试 前言 Faster-LIO是基于FastLIO2开发的。FastLIO2是开源LIO中比较优秀的一个&#xff0c;前端用了增量的kdtree&#xff08;ikd-tree&#xff09;&#xff0c;后端用了迭代ESKF&#xff08;IEKF&a…

VS2022 配置Qt编译环境 | winows安装Qt5.14.2 | VS2017和Qt5配置成功指南

Visual Studio 2022安装教程完文本内容较多,请耐心看完,挺有收获的,要自己多尝试哦。 文章目录 # 插件安装 如果你想用VS2022来创建QT项目,那么你首先要学会下面的操作,创建一个空白解决方案,在扩展搜索qt,并且下载两个插件(带有绿√的就是)。这里其实是一个坑:VS20…

智慧校园:打造未来教育新时代

智慧校园&#xff1a;打造未来教育新时代 智慧校园是指利用先进的信息技术手段&#xff0c;通过云计算、大数据分析、人工智能等技术来提升教育教学质量和管理效率的一种模式。随着科技的不断发展&#xff0c;智慧校园正成为教育领域的热门话题。本文将深入探讨智慧校园的定义、…

leetCode 90.子集 II + 回溯算法 + 图解 + 笔记

给你一个整数数组 nums &#xff0c;其中可能包含重复元素&#xff0c;请你返回该数组所有可能的子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。返回的解集中&#xff0c;子集可以按 任意顺序 排列 示例 1&#xff1a; 输入&#xff1a;nums [1,2,2] 输出…

如何优雅的进行业务分层

1.什么是应用分层 说起应用分层&#xff0c;大部分人都会认为这个不是很简单嘛 就controller&#xff0c;service, mapper三层。 看起来简单&#xff0c;很多人其实并没有把他们职责划分开&#xff0c;在很多代码中&#xff0c;controller做的逻辑比service还多,service往往当…

Mysql的页结构详解

1.数据库的存储结构&#xff1a;页 索引结构为我们提供了搞笑的查找方式&#xff0c;索引信息和数据记录都在保存在文件上的&#xff0c;准确地说&#xff0c;是保存在“页”结构中。 1.1磁盘与内存的基本交互单位&#xff1a;页 InnoDB将数据划分为若干个页&#xff0c;Inn…

2023年中国消费金融行业研究报告

第一章 行业概况 1.1 定义 中国消费金融行业&#xff0c;作为国家金融体系的重要组成部分&#xff0c;旨在为消费者提供多样化的金融产品和服务&#xff0c;以满足其消费需求。这一行业包括银行、消费金融公司、小额贷款公司等多种金融机构&#xff0c;涵盖了包括消费贷款在内…

html实现各种好看的鼠标滑过图片特效模板

文章目录 1.鼠标悬浮效果1.1 渐动效果1.2 渐变效果1.3 边框效果1.4 线行效果1.5 图标效果1.6 块状效果1.7 边线效果1.8 放大效果1.9 渐出效果1.10 痕迹效果1.11 交叉效果1.12 着重效果1.13 详展效果1.14 能动效果1.15 明细效果 2.主要源码2.1 源代码 源码下载 作者&#xff1a;…

Java-easyExcel入门教程

文章目录 前言一、简介二、使用步骤1. 引入依赖2. 前提准备3. 实现导出4. 实现导入 三、我所遇到的问题四、总结 前言 在日常开发中经常会遇到一些 excel 表导入导出的需求&#xff0c;以往会使用 POI 封装成工具类来处理这些导入导出的需求&#xff0c;但是 POI 在导入大文件…

Docker 环境中 Spring Boot 应用的 Arthas 故障排查与性能优化实战

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

【零基础入门Docker】Dockerfile中的USER指令以及dockerfile命令详解

✍面向读者&#xff1a;所有人 ✍所属专栏&#xff1a;Docker零基础入门专栏 目录 第 1 步&#xff1a;创建 Dockerfile 第 2 步&#xff1a;构建 Docker 镜像 第 3 步&#xff1a;运行 Docker 容器 第 4 步&#xff1a;验证输出 dockerfile命令详解 最佳实践 默认情况下…

matlab 基于卡尔曼滤波的GPS-INS的数据融合的导航

1、内容简介 略 25-可以交流、咨询、答疑 2、内容说明 基于卡尔曼滤波的GPS-INS的数据融合的导航 "基于卡尔曼滤波的GPS-INS的数据融合的导航 基于卡尔曼滤波实现GPS-INS组合导航系统" 卡尔曼滤波、GPS、INS、数据融合、导航 3、仿真分析 4、参考论文 略 …

[github全教程]github版本控制最全教学------- 大厂找工作面试必备!

作者&#xff1a;20岁爱吃必胜客&#xff08;坤制作人&#xff09;&#xff0c;近十年开发经验, 跨域学习者&#xff0c;目前于新西兰奥克兰大学攻读IT硕士学位。荣誉&#xff1a;阿里云博客专家认证、腾讯开发者社区优质创作者&#xff0c;在CTF省赛校赛多次取得好成绩。跨领域…

如何精准操作无人机自动停机坪?

无人机自动停机坪通过自主导航和避障功能&#xff0c;实现了无人机的自主降落和起飞&#xff0c;在无人机技术领域起到了至关重要的作用。停机坪不仅仅是无人机的起降平台&#xff0c;还具备自动换电或充电等功能&#xff0c;为无人机的自动化提供了关键支持。为更有效地操作无…

ESP32-Web-Server编程-CSS 基础 2

ESP32-Web-Server编程-CSS 基础 2 概述 如上节所述&#xff0c;可以使用外部 CSS 文件来修饰指定的 HTML 文件。 外部引用 - 使用外部 CSS 文件。 当样式需要被应用到很多页面的时候&#xff0c;外部样式表将是理想的选择。使用外部样式表&#xff0c;就可以通过更改一个文件…