Mybatis枚举类型处理和类型处理器
专栏精选
引入Mybatis
Mybatis的快速入门
Mybatis的增删改查扩展功能说明
mapper映射的参数和结果
Mybatis复杂类型的结果映射
Mybatis基于注解的结果映射
Mybatis枚举类型处理和类型处理器
再谈动态SQL
Mybatis配置入门
Mybatis行为配置之Ⅰ—缓存
Mybatis行为配置之Ⅱ—结果相关配置项说明
Mybatis行为配置之Ⅲ—其他行为配置项说明
Mybatis行为配置之Ⅳ—日志
Mybatis整合Spring详解
Mybatis插件入门
Mybatis专栏代码资源
文章目录
- 专栏精选
- 摘要
- 引言
- 正文
- 枚举类型映射
- 简单枚举映射
- 枚举顺序映射
- 复杂枚举映射
- 类型处理器
- 总结
摘要
在这篇文章中,我们将进入Mybatis类型转换器的世界,了解Mybatis中如何使用枚举类型和Mybatis类型转换器的基本用法,其中的很多观点或内容都能在一定程度上让我们的开发之旅更加轻松方便,这是一个菜鸟提升技术能力,老鸟巩固基础知识的好机会。准备好开启今天的神奇之旅了吗?
引言
大家好,我是奇迹老李,一个专注于分享开发经验和基础教程的博主。这里是我的其中一个技术分享平台,欢迎广大朋友们点赞评论提出意见,重要的是点击关注喔 🙆。今天要和大家分享的内容是枚举类型处理和类型处理器。做好准备,Let’s go🚎🚀
正文

枚举类型映射
简单枚举映射
如果需要返回枚举类型的查询结果,如果返回值和枚举值一一对应,可以直接使用枚举类型接收返回结果。
新增字典数据
INSERT INTO dict_test (dict_name, dict_code, dict_type, dict_sort) VALUES ('NONE', '1', 'app_auth_type', 0);
INSERT INTO dict_test (dict_name, dict_code, dict_type, dict_sort) VALUES ('MOBILE', '2', 'app_auth_type', 2);
INSERT INTO dict_test (dict_name, dict_code, dict_type, dict_sort) VALUES ('WECHAT', '3', 'app_auth_type', 3);
INSERT INTO dict_test (dict_name, dict_code, dict_type, dict_sort) VALUES ('QQ', '4', 'app_auth_type', 4);
新增枚举类
public enum AuthType { NONE,WECHAT,QQ,MOBILE;
}
mapper映射
AuthType getAuthType(@Param("code")String code);
<select id="getAuthType" resultType="top.sunyog.common.entity.AuthType"> select dict_name from dict_test where dict_type='app_auth_type' and dict_code=#{code}
</select>
测试类
private void testEnumResultService(SimpleQueryMapper mapper){ AuthType authType = mapper.getAuthType("3"); System.out.println(authType);
}
打印结果
WECHAT
枚举顺序映射
mybatis内置了EnumOrdinalTypeHandler类型处理器,来实现字典顺序号和枚举类型之间的映射。注意枚举类型的顺序号从0开始。
代码示例:
mapper-xml
<resultMap id="app-auth-order" type="map"> <result property="auth_type" column="auth_type" javaType="top.sunyog.common.entity.AuthType" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>
</resultMap>
<select id="getAppAuthOrder" resultMap="app-auth-order"> select auth_type from app_test where id=#{id}
</select>
mapper接口
Map<String,Object> getAppAuthOrder(@Param("id") Long id);
测试类:
public class SimpleQueryService extends MybatisService<SimpleQueryMapper>{private void testEnumOrdder(SimpleQueryMapper mapper) { Map<String, Object> map = mapper.getAppAuthOrder(2L); map.entrySet().forEach(o-> System.out.println(o.getKey()+": "+o.getValue())); }
}
打印结果(auth_type=2)
auth_type: QQ
复杂枚举映射
对于返回值和枚举名称不对应的情况,可以使用自定义类型处理器的方式解决,
在类型处理器中处理数据库数据和枚举类型之间的对应关系
自定义类型处理器
public class AppAuthTypeHandler extends BaseTypeHandler<AppStatus> { @Override public void setNonNullParameter(PreparedStatement ps, int i, AppStatus parameter, JdbcType jdbcType) throws SQLException { ps.setString(i,this.appStatusToString(parameter)); } @Override public AppStatus getNullableResult(ResultSet rs, String columnName) throws SQLException { String str = rs.getString(columnName); return this.stringToAppStatus(str); } @Override public AppStatus getNullableResult(ResultSet rs, int columnIndex) throws SQLException { String str = rs.getString(columnIndex); return this.stringToAppStatus(str); } @Override public AppStatus getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { String str = cs.getString(columnIndex); return this.stringToAppStatus(str); } private String appStatusToString(AppStatus status){ switch (status){ case FREEZE: return "冻结应用"; case NORMAL: return "正常应用"; case OVERDUE: return "过期应用"; case TEMPORARY: default: return "临时应用"; } } private AppStatus stringToAppStatus(String str){ switch (str){ case "冻结应用": return AppStatus.FREEZE; case "正常应用": return AppStatus.NORMAL; case "过期应用": return AppStatus.OVERDUE; default: return AppStatus.TEMPORARY; } }
}
定义新的结果值类型
public class AppDict { private AppStatus appStatus; public AppStatus getAppStatus() { return appStatus; } public void setAppStatus(AppStatus appStatus) { this.appStatus = appStatus; } @Override public String toString() { return "AppDict{" + "appStatus=" + appStatus + '}'; }
}
新增mapper方法
AppDict getAppStatusEnum(@Param("code")String code);
定义映射文件,通过resultMap设置类型处理器
<resultMap id="app-status-enum" type="top.sunyog.common.entity.AppDict"> <result property="appStatus" column="dict_name" typeHandler="top.sunyog.mybatis.handler.AppAuthTypeHandler"/>
</resultMap>
<select id="getAppStatusEnum" resultMap="app-status-enum"> select dict_name from dict_test where dict_type='app_status' and dict_code=#{code}
</select>
测试代码
private void testEnumStatusService(SimpleQueryMapper mapper){ AppDict appDict = mapper.getAppStatusEnum("1"); System.out.println(appDict);
}
打印结果
AppDict{appStatus=FREEZE}
类型处理器
以上对复杂枚举映射的解决方式即是类型处理器的简单应用,在开发过程中更常见的是对LocalDateTime等事件类型的转换。
这是因为在Mybatis的早期版本中,对于日期类型的数据通常使用
Java.util.Date类型接收,如果使用java.time.LocalDateTime类型接收该字段会造成结果值为空的情况,这时候要么升级Mybatis版本,要么通过自定义类型处理器实现
降低mybatis版本到3.4.4
<dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.4</version> </dependency>
</dependencies>
此时重新启动项目会报错,需要修改启动类
public class MybatisAppContext { private static SqlSessionFactory sqlSessionFactory = null; private Map<String, MybatisService> serviceMap = new ConcurrentHashMap<>(); /** * 注册SqlSessionFactory */ static { SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); try (InputStream in = MybatisApp.class.getResourceAsStream("/mybatis-config.xml"); InputStreamReader reader=new InputStreamReader(in)) { sqlSessionFactory = builder.build(reader); } catch (IOException e) { System.out.println("文件路径读取错误"); } }...
}
此时再启动项目仍会报错,提示没有对应的类处理器
新增类型处理器 LocalDateHandler
package top.sunyog.mybatis.handler; import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType; import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate; public class LocalDateHandler extends BaseTypeHandler<LocalDate> { @Override public void setNonNullParameter(PreparedStatement ps, int i, LocalDate parameter, JdbcType jdbcType) throws SQLException { ps.setObject(i,parameter); } @Override public LocalDate getNullableResult(ResultSet rs, String columnName) throws SQLException { return rs.getObject(columnName,LocalDate.class); } @Override public LocalDate getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return rs.getObject(columnIndex,LocalDate.class); } @Override public LocalDate getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return cs.getObject(columnIndex,LocalDate.class); }
}
配置文件添加配置项typeHandler
<settings .../>
<typeAliasis .../><typeHandlers> <typeHandler handler="top.sunyog.mybatis.handler.LocalDateHandler"/>
</typeHandlers><environments .../><mappers .../>
测试代码
public class SimpleQueryService extends MybatisService<SimpleQueryMapper>{ @Override public void doService() { SimpleQueryMapper mapper = super.getMapper(SimpleQueryMapper.class); this.testHashMapParam(mapper);}
}
打印结果
AppTestEntity{id=5, appName='名称1', appCode='code-1', authType='2', createDate=2023-11-03, creator='admin3', appStatus='null', authTypeDict=null, appStatusDict=null, services=null}
AppTestEntity{id=6, appName='name2', appCode='code-2', authType='2', createDate=2023-11-03, creator='admin3', appStatus='null', authTypeDict=null, appStatusDict=null, services=null}
AppTestEntity{id=7, appName='jack liu', appCode='code-3', authType='2', createDate=2023-11-03, creator='admin3', appStatus='null', authTypeDict=null, appStatusDict=null, services=null}
注意:以上处理方式只能解决由于Mybatis版本原因造成的LocalDateTime或LocalDate等的类型转换失败问题。但类型转换失败有可能是数据库驱动、或连接池的版本问题造成的,实际开发过程中遇到过在Oracle数据库中ojdbc7驱动接收LocalDateTime类时间数据失败报错的问题,一般通过升级到ojdbc8都能解决。如果项目版本升级比较麻烦,可以使用Date类型接收日期时间数据,在service层再做转换或不转换,通过@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone="GMT+8")注解的方式指定时区保证时间的准确性
总结
本文我们介绍了在Mybatis中如何使用枚举类型接收查询结果,并以此引入Mybatis 的类型处理器。通过日期类型处理器类认识了类型处理器的简单使用,在业务开发过程中,可以通过设计功能更强大的类型处理器来更优雅的实现各种相关业务需求。
我们在Mybatis的增删改查扩展功能说明这篇文章最后提到的疑问4和疑问5也得到了解决。
📩 联系方式
邮箱:qijilaoli@foxmail.com❗版权声明
本文为原创文章,版权归作者所有。未经许可,禁止转载。更多内容请访问奇迹老李的博客首页
相关文章:
Mybatis枚举类型处理和类型处理器
专栏精选 引入Mybatis Mybatis的快速入门 Mybatis的增删改查扩展功能说明 mapper映射的参数和结果 Mybatis复杂类型的结果映射 Mybatis基于注解的结果映射 Mybatis枚举类型处理和类型处理器 再谈动态SQL Mybatis配置入门 Mybatis行为配置之Ⅰ—缓存 Mybatis行为配置…...
2023 NCTF writeup
CRYPTO Sign 直接给了fx,gx,等于私钥给了,直接套代码,具体可以参考: https://0xffff.one/d/1424 fx [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…...
golang的大杀器协程goroutine
在Golang中,协程(Goroutine)是轻量级的执行单元,用于实现并发编程。它是Golang语言的重要组成部分,提供了简洁、高效的方式来处理并发任务。 特点: 1)轻量级:Go语言的协程是轻量级…...
[Angular] 笔记 9:list/detail 页面以及@Output
1. Output input 好比重力,向下传递数据,list 传给 detail,smart 组件传给 dumb 组件,父组件传给子组件。input 顾名思义,输入数据给组件。 output 与之相反,好比火箭,向上传递数据或事件。ou…...
Linux学习笔记(一)
如果有自己的物理服务器请先查看这篇文章 文章目录 网卡配置Linux基础指令ls:列出目录内容cd(mkdir.rmkdir): 切换文件夹(创建,删除操作)cp:复制文件或目录mv:文件/文件夹移动cat:查看文件vi:文件查看编辑man:查看命令手册more: 查看文件内容less : 查看文件内容 ps: 显示当前进…...
Python 爬虫 教程
python爬虫框架:Scrapyd,Feapder,Gerapy 参考文章: python爬虫工程师,如何从零开始部署ScrapydFeapderGerapy? - 知乎 神器!五分钟完成大型爬虫项目 - 知乎 爬虫框架-feapder - 知乎 scrap…...
uniapp原生插件 - android原生插件打包流程 ( 避坑指南一)
【彩带- 避坑知识点】: 当时开发中安卓插件打包成功后,uniapp引用插件aar,用云打包 ,总是提示不包含插件。原因是因为module的androidManifest.xml文件没有注册activity。 这一步 很重要,一定要注册。 --------------------------…...
搭建maven私服
maven maven简介 什么是maven? Maven这个单词来自于意第绪语(犹太语),意为知识的积累。 Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件。 Maven 除了以…...
EST-100身份证社保卡签批屏按捺终端PC版web版本http协议接口文档,支持web网页开发对接使用
<!DOCTYPE html><html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width,initial-scale1.0"><title>演示DEMO</title><script type"text/…...
基于SpringBoot的毕业论文管理系统
文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于SpringBoot的毕业论文管理系统,java…...
iToF人脸识别
iToF(间接飞行时间)是一种测量光飞行时间的技术,主要应用于人脸识别。 iToF人脸识别技术在哪些场景下会用到 iToF人脸识别技术可以应用于许多场景,以下是一些常见的应用场景: 平安城市:在城市监控系统中,iToF人脸识别技术可以用于实时监控、目标检测和识别,以及异常行为…...
Django开发3
Django开发3 Django开发编辑用户9.靓号管理9.1 表结构9.2 靓号列表9.3 新建靓号9.4 编辑靓号9.5 搜索手机号9.6 分页 10.时间插件11.ModelForm和BootStrap操作 各位小伙伴想要博客相关资料的话关注公众号:chuanyeTry即可领取相关资料! Django开发 部门管…...
MS2358:96KHz、24bit 音频 ADC
产品简述 MS2358 是带有采样速率 8kHz-96kHz 的立体声音频模数 转换器,适合于面向消费者的专业音频系统。 MS2358 通过使用增强型双位 Δ - ∑ 技术来实现其高精度 的特点。 MS2358 支持单端的模拟输入,所以不需要外部器 件,非常适…...
【Android12】Android Framework系列---tombstone墓碑生成机制
tombstone墓碑生成机制 Android中程序在运行时会遇到各种各样的问题,相应的就会产生各种异常信号,比如常见的异常信号 Singal 11:Segmentation fault表示无效的地址进行了操作,比如内存越界、空指针调用等。 Android中在进程(主要…...
中间件系列 - Redis入门到实战(原理篇)
前言 学习视频: 黑马程序员Redis入门到实战教程,深度透析redis底层原理redis分布式锁企业解决方案黑马点评实战项目 中间件系列 - Redis入门到实战 本内容仅用于个人学习笔记,如有侵扰,联系删除 学习目标 Redis数据结构Redis网…...
P2249 【深基13.例1】查找
P2249 【深基13.例1】查找 P2249 【深基13.例1】查找 题意 输入n 个不超过10的9次方的单调不减的(就是后面的数字不小于前面的数字)非负整数a1,a2,a3…然后进行 m 次询问。对于每次询问,给出一个整数q,要…...
linux常用shell脚本
查看系统当前进程连接数 netstat -an | grep ESTABLISHED | wc -l 如何在/usr目录下找出大小超过10MB的文件? find /usr -type f -size 10240k 添加一条到192.168.3.0/24的路由,网关为192.168.1.254? route add -net 192.168.3.0/24 netmask 255.2…...
Rust学习笔记005:结构体 struct
在 Rust 中,struct 是一种用于创建自定义数据类型的关键字,它允许你定义和组织数据的结构。struct 可以包含多个不同类型的字段(fields),每个字段都有一个名称和一个类型。 定义结构体 下面是一个简单的例子ÿ…...
maven中dependencyManagement标签
简介 dependencyManagement正如其名,用于项目依赖的统一管理。 在父项目中的pom.xml文件中加入dependencyManagement标签即可完成依赖版本的声明。在声明完成后,子项目(module)中引用相同的依赖时可以不指定version标签自动引入…...
SparkStreaming与Kafka整合
1.3 SparkStreaming与Kafka整合 1.3.1 整合简述 kafka是做消息的缓存,数据和业务隔离操作的消息队列,而sparkstreaming是一款准实时流式计算框架,所以二者的整合,是大势所趋。 二者的整合,有主要的两大版本。 kaf…...
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...
C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...
