Mybatis--TypeHandler使用手册

news2025/1/15 6:46:51

TypeHandler使用手册

场景:想保存user时 teacher自动转String ,不想每次保存都要手动去转String;从DB查询出来时,也要自动帮我们转换成Java对象 Teacher

@Data
public class User {

    private Integer id;

    private String name;

    private Integer sex;
    
    //这里直接使用数据库无法识别的自定义类型
    private Teacher teacher;
}

当然Mybatis给我们提供了接口 TypeHandler(类型映射)

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;
}

看看mybatis内置的类型处理器,这就是为什么一些Java的数据类型不用我们手动转换的原因
在这里插入图片描述

我们可以参考String,看他是怎么处理的,发现都是通过原生的jdbc来处理的

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);
  }
}
实战

我们结合springboot来看,启动容器

server:
  port: 8080
mybatis:
  mapper-locations: classpath:mappers/*.xml
  type-handlers-package: com.example.ssm.demos.web.typeHandler

创建SqlSessionFactory的时候扫描并注册

public class SqlSessionFactoryBean implements InitializingBean {
    
  @Override
  public void afterPropertiesSet() throws Exception {
    this.sqlSessionFactory = buildSqlSessionFactory();
  }
    
  protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
    if (hasLength(this.typeHandlersPackage)) {
      //在包路径下找到实现TypeHandler的类并注册
      scanClasses(this.typeHandlersPackage, TypeHandler.class).stream().filter(clazz -> !clazz.isAnonymousClass())
          .filter(clazz -> !clazz.isInterface()).filter(clazz -> !Modifier.isAbstract(clazz.getModifiers()))
          .forEach(targetConfiguration.getTypeHandlerRegistry()::register);
    }
  }
}

注册并加入缓存

public final class TypeHandlerRegistry {
  private final Map<Type, Map<JdbcType, TypeHandler<?>>> typeHandlerMap = new ConcurrentHashMap<>();
  private final Map<Class<?>, TypeHandler<?>> allTypeHandlersMap = new HashMap<>();
    
  public void register(Class<?> typeHandlerClass) {
    boolean mappedTypeFound = false;
    //如果这个类有注解@MappedTypes,根据注解的指定的类进行有参构造实例化
    MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class);
    if (mappedTypes != null) {
      for (Class<?> javaTypeClass : mappedTypes.value()) {
        register(javaTypeClass, typeHandlerClass);
        mappedTypeFound = true;
      }
    }
    //没有注解,直接无参构造实例化
    if (!mappedTypeFound) {
      register(getInstance(null, typeHandlerClass));
    }
  }
    
   //加入缓存 
   private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {
    if (javaType != null) {
      Map<JdbcType, TypeHandler<?>> map = typeHandlerMap.get(javaType);
      if (map == null || map == NULL_TYPE_HANDLER_MAP) {
        map = new HashMap<>();
      }
      map.put(jdbcType, handler);
      typeHandlerMap.put(javaType, map);
    }
    allTypeHandlersMap.put(handler.getClass(), handler);
  }
}

容器启动完成,测试一下

@Mapper
public interface UserMapper {
    public User getUserListByEntity(Integer id);
    public int insertUser(User user);
}

定义一个Teacher 处理器

public class TeacherTypeHandler extends BaseTypeHandler<Teacher> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Teacher parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, JSON.toJSONString(parameter));
    }

    @Override
    public Teacher getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return JSON.parseObject(rs.getString(columnName),Teacher.class);
    }

    @Override
    public Teacher getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return JSON.parseObject(rs.getString(columnIndex),Teacher.class);
    }

    @Override
    public Teacher getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return JSON.parseObject(cs.getString(columnIndex),Teacher.class);
    }
}

mapper文件

<?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.example.ssm.demos.web.mapper.UserMapper">
    <sql id="allUserCollun">
        id,name,sex,teacher
    </sql>
    <resultMap id="userMap" type="com.example.ssm.demos.web.pojo.User">
        <id column="id" property="id"></id>
        <result property="name" column="name"></result>
        <result property="sex" column="sex"></result>
        <!-- 指定字段处理器,反序列化成Teacher对象 -->
        <result property="teacher" column="teacher" typeHandler="com.example.ssm.demos.web.typeHandler.TeacherTypeHandler" ></result>
    </resultMap>
    
    <!-- 测试查询 -->
    <select id="getUserListByEntity" resultMap="userMap">
        select
            <include refid="allUserCollun"></include>
        from User
        <where>
            id = #{id}
        </where>
    </select>
    
    <!-- 测试新增 -->
    <insert id="insertUser" parameterType="com.example.ssm.demos.web.pojo.User">
        insert into user(
            <include refid="allUserCollun"></include>
        ) values (
        #{id},#{name},#{sex},
        <!-- 指定字段处理器,转换成json格式的字符串 -->
        #{teacher,typeHandler=com.example.ssm.demos.web.typeHandler.TeacherTypeHandler})
    </insert>
</mapper>

经过测试,完全没有问题,插入数据库时,自动转 String,查询时,自动转 Teacher

在这里插入图片描述

如果想知道调用位置,参数可以看这个类: org.apache.ibatis.scripting.defaults.DefaultParameterHandler#setParameters

返回值可以看这个类: org.apache.ibatis.executor.resultset.DefaultResultSetHandler#getPropertyMappingValue

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

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

相关文章

gpt国内怎么用?最新版本来了

claude 3 opus面世后&#xff0c;这几天已经有许多应用&#xff0c;而其精确以及从不偷懒&#xff08;截止到2024年3月11日还没有偷懒&#xff09;的个性&#xff0c;也使得我们可以用它来首次完成各种需要多轮对话的尝试。 今天我们想要进行的一项尝试就是—— 如何从一个不知…

PWM技术的应用

目录 PWM技术简介 PWM重要参数 PWM实现呼吸灯 脉宽调制波形 PWM案例 电路图 keil文件 直流电机 直流电机的控制 直流电机的驱动芯片L293D L293D引脚图 L293D功能表 直流电机案例 电路图 keil文件 步进电机 步进电机特点 步进电机驱动芯片L298 L298引脚图 L…

MySQL、Oracle查看字节和字符长度个数的函数

目录 0. 总结1. MySQL1.1. 造数据1.2. 查看字符/字节个数 2. Oracle2.1. 造数据2.2. 查看字符/字节个数 0. 总结 databasecharbyteMySQLchar_length()length()Oraclelength()lengthB() 1. MySQL 1.1. 造数据 sql drop table if exists demo; create table demo (id …

c++宏有什么离谱操作?

Boost.Preprocessor确实是一个非常强大而复杂的C宏库&#xff0c;专门用于元编程&#xff0c;即在编译时进行代码生成和变换。我这里有一套编程入门教程&#xff0c;不仅包含了详细的视频讲解&#xff0c;项目实战。如果你渴望学习编程不妨点个关注&#xff0c;给个评论222&…

卷积神经网络-池化层

卷积神经网络-池化层 池化层&#xff08;Pooling Layer&#xff09;是深度学习神经网络中的一个重要组成部分&#xff0c;通常用于减少特征图的空间尺寸&#xff0c;从而降低模型复杂度和计算量&#xff0c;同时还能增强模型的不变性和鲁棒性。 池化操作通常在卷积神经网络&am…

Nativefier - 将网页变为软件

Nativefier 是一款命令行工具&#xff0c;可以轻松地为任何网站创建 "桌面应用程序"&#xff0c;而无需大费周章。应用程序由 Electron&#xff08;内核使用 Chromium&#xff09;封装成操作系统可执行文件&#xff08;.app、.exe 等&#xff09;&#xff0c;可在 Wi…

GD32F470_MQ-2烟雾检测传感器模块移植

2.5 MQ-2烟雾检测传感器 MQ-2型烟雾传感器属于二氧化锡半导体气敏材料&#xff0c;属于表面离子式N型半导体。处于200~3000摄氏度时&#xff0c;二氧化锡表面吸附空气中的氧&#xff0c;形成氧的负离子吸附&#xff0c;使半导体中的电子密度减少&#xff0c;从而使其电阻值增加…

接口的总结与面试题

接口本身不能创建对象&#xff0c;只能创建接口的实现类对象&#xff0c;接口类型的变量可以与实现类对象构成多态引用。 声明接口用interface&#xff0c;接口的成员声明有限制&#xff1a; &#xff08;1&#xff09;公共的静态常量 &#xff08;2&#xff09;公共的抽象方…

LeetCode-热题100:2. 两数相加

题目描述 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff0c;这两个数都…

基于springboot大学生兼职平台管理系统(完整源码+数据库)

一、项目简介 本项目是一套基于springboot大学生兼职平台管理系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、功…

LabVIEW电动汽车供电设备接触电流测试

LabVIEW电动汽车供电设备接触电流测试 随着电动汽车技术的迅猛发展和普及率的不断提高&#xff0c;电动汽车供电设施的电气安全显得尤为重要。为了优化电动汽车供电设备接触电流的测试方案&#xff0c;设计了一种基于LabVIEW的测试方案&#xff0c;通过平台校准测试和电动汽车…

Linux第2课Windows下的环境配置-虚拟机安装

文章目录 Linux第2课Windows下的环境配置-虚拟机安装一、VMware虚拟机的安装&#xff08;一&#xff09;安装VMware&#xff08;二&#xff09;启动电脑本地的VMware相关服务 二、VirtualBox安装 Linux第2课Windows下的环境配置-虚拟机安装 本节课程提供了两种虚拟机的安装方法…

程序员延寿指南:科学延寿 20 年 | 开源日报 No.214

geekan/HowToLiveLonger Stars: 28.7k License: Unlicense HowToLiveLonger 是一个程序员延寿指南项目。 该项目旨在提供关于如何延长寿命的指南&#xff0c;特别是针对程序员群体。该项目包括术语、目标、关键结果、分析、行动和证据等内容&#xff0c;涵盖了各种与健康相关的…

不同路径- java

题目描述: 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的路径&#xff…

模块化编程:AMD 和 CMD 的魅力

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

特定领域软件体系结构

1.DSSA的定义 简单地说&#xff0c;DSSA&#xff08;Domain Specific Software Architecture&#xff09;就是在一个特定应用领域中为一组应用提供组织结构参考的标准软件体系结构。 从功能覆盖的范围的角度有两种理解DSSA中领域的含义的方式&#xff1a; &#xff08;1&#x…

前端三剑客 —— CSS ( 坐标问题 、定位问题和图片居中 )

前期内容回顾&#xff1a; 1.常见样式 text-shadow x轴 y轴 阴影的模糊程度 阴影的颜色 box-shadow border-radio 实现圆角 margin 内边距 padding 外边距 background 2.特殊样式 媒体查询&#xff1a;media 自定义字体&#xff1a;font-face { font-family:自定义名称&#…

【随笔】Git -- 高级命令(中篇)(七)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…

BioMedKGs:算法生成医学知识图谱,解决构建和维护工作量巨大问题

BioMedKGs&#xff1a;算法生成医学知识图谱&#xff0c;解决构建和维护工作量巨大问题 提出背景对比传统方法 算法设计3.1 自动化命名实体识别&#xff08;NER&#xff09;3.2 术语发现与清洗3.3 同义词分组形成概念3.4 多语言、机器翻译3.5 语义类型分类3.6 关系提取3.7 数据…

ArcGIS 10.8中文版详细安装教程(附安装包)

ArcGIS 10.8中文版详细安装教程&#xff08;附安装包&#xff09; 关键词&#xff1a;ArcGIS 10.8中文版安装 1.概述 ArcGIS Desktop 10.8中文版是由ESRI公司开发的一款专业的地理信息系统&#xff0c;一套完整的桌面GIS软件套件&#xff0c;它包含ArcMap、ArcCatalog、ArcG…