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版本原因造成的LocalDateTimeLocalDate等的类型转换失败问题。但类型转换失败有可能是数据库驱动、或连接池的版本问题造成的,实际开发过程中遇到过在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

❗版权声明
本文为原创文章,版权归作者所有。未经许可,禁止转载。更多内容请访问奇迹老李的博客首页

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

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

相关文章

Postman!IDEA中也能用!

Postman是大家最常用的API调试工具&#xff0c;那么有没有一种方法可以不用手动写入接口到Postman&#xff0c;即可进行接口调试操作&#xff1f;今天给大家推荐一款IDEA插件&#xff1a;Apipost Helper&#xff0c;写完代码就可以调试接口并一键生成接口文档&#xff01;而且还…

「微服务」Saga 模式 如何使用微服务实现业务事务-第二部分

在上一篇文章中&#xff0c;我们看到了实现分布式事务的一些挑战&#xff0c;以及如何使用Event / Choreography方法实现Saga的模式。在本文中&#xff0c;我们将讨论如何通过使用另一种类型的Saga实现&#xff08;称为Command或Orchestration&#xff09;来解决一些问题&#…

2024年原创深度学习算法项目分享

原创深度学习算法项目分享&#xff0c;包括以下领域&#xff1a; 图像视频、文本分析、知识图谱、推荐系统、问答系统、强化学习、机器学习、多模态、系统界面、爬虫、增量学习等领域… 有需要的话&#xff0c;评论区私聊

Unity Meta Quest 一体机开发(十二):【手势追踪】Poke 交互 - 用手指点击由 3D 物体制作的 UI 按钮

文章目录 &#x1f4d5;教程说明&#x1f4d5;给玩家配置 HandPokeInteractor&#x1f4d5;用 3D 物体制作可以被点击的 UI 按钮⭐搭建物体层级⭐给物体添加脚本⭐为脚本变量赋值 &#x1f4d5;模仿官方样例按钮的样式&#x1f4d5;在按钮上添加文字&#x1f4d5;修改按钮图片 …

linux安装rabbitmq

文章目录 前言一、下载安装包二、erlang1.安装依赖2.解压3.安装4.环境变量5.验证 三、rabbitmq1.安装依赖2.解压3.新建目录4.rabbitmq.env.conf5.rabbitmq.conf6.环境变量7.启动8.验证9.停止 四、安装web1.安装插件2.访问控制台界面 五、开机启动1.编写脚本2.设置开机启动3.测试…

c语言-string.h库函数初识

目录 前言一、库函数strlen()1.1 strlen()介绍1.2 模拟实现strlen() 二、库函数strcpy()2.1 strcpy()介绍2.2 模拟实现strcpy() 三、库函数strcmp()3.1 strcmp()介绍3.3 模拟实现strcmp() 总结 前言 本篇文章介绍c语言<string.h>头文件中的库函数&#xff0c;包含strlen…

从仿写持久层框架到MyBatis核心源码阅读

接上篇手写持久层框架&#xff1a;https://blog.csdn.net/liwenyang1992/article/details/134884703 MyBatis源码 MyBatis架构原理&主要组件 MyBatis架构设计 MyBatis架构四层作用是什么呢&#xff1f; API接口层&#xff1a;提供API&#xff0c;增加、删除、修改、查询…

Matlab技巧[绘画逻辑分析仪产生的数据]

绘画逻辑分析仪产生的数据 逻分上抓到了ADC数字信号,一共是10Bit,12MHZ的波形: 这里用并口协议已经解析出数据: 导出csv表格数据(这个数据为补码,所以要做数据转换): 现在要把这个数据绘制成波形,用Python和表格直接绘制速度太慢了,转了一圈发现MATLAB很好用,操作方法如下:…

若依(Spring boot)框架中如何在不同的控制器之间共享与使用数据

在若依框架或Spring boot框架中&#xff0c;控制器共享和使用数据是为了确保数据一致性、传递信息、提高效率和降低系统复杂性。这可以通过全局变量、依赖注入或数据库/缓存等方式实现。共享和使用数据对框架的正常运行非常关键&#xff0c;有助于促进控制器之间的协同工作&…

阶段十-分布式-nginx服务器

一、Nginx简介 Nginx 是高性能的 HTTP 和反向代理的服务器&#xff0c;处理高并发能力是十分强大的&#xff0c;能经受高负载的考验,有报告表明能支持高达 50,000 个并发连接数。tomcat并发数量理论值是500&#xff0c;实际也就300左右。 1.2 正向代理 正向代理代理的是客户…

OpenGL FXAA抗锯齿算法(Qt)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 之前已经提供了使用VCG读取Mesh的方式,接下来就需要针对读取的网格数据进行一些渲染操作了。在绘制Mesh数据时总会遇到图形的抗锯齿问题,OpenGL本身已经为我们提供了一种MSAA技术,但该技术对于一些实时渲染性能有…

产品经理学习-从0-1搭建策略产品

从0-1搭建策略产品 目录&#xff1a; 回顾策略产品 如何从0-1搭建策略产品 回顾策略产品 之前也了解过从产品实施的角度来看&#xff0c;策略就是针对问题的解决方案&#xff0c;在互联网时代更集中体现在2个维度&#xff1a;业务场景和数据应用 如何从0-1搭建策略产品 我们…

交叉验证的种类和原理(sklearn.model_selection import *)

交叉验证的种类和原理 所有的来自https://scikit-learn.org/stable/modules/cross_validation.html#cross-validation-iterators并掺杂了自己的理解。 文章目录 前言一、基础知识1.1 交叉验证图形表示1.2 交叉验证主要类别 二、部分交叉验证函数&#xff08;每类一个&#xff0…

如何在VSCode搭建ESP-IDF开发ESP32

文章目录 概要安装VScode安装ESP-IDF插件使用官方例程小结 概要 ESP-IDF(Espressif IoT Development Framework) 即乐鑫物联网开发框架&#xff0c;它基于 C/C 语言提供了一个自给自足的 SDK&#xff0c;可为在 Windows、Linux 和 macOS 系统平台上开发 ESP32 应用程序提供工具…

旅游平台网页前后端

功能清单 游客功能 用户注册、登录登录权限拦截按名称搜索房间支付流程查看订单信息和状态评论预定过的房间&#xff0c;并自动修改订单状态查看统计剩余房间数量&#xff0c;数量为0时不可预定 管理员功能 房间分类管理 类型的删除、修改、查询&#xff08;准备添加增添功能…

3D展2D数学原理

今年早些时候&#xff0c;我为 MAKE 杂志写了一篇教程&#xff0c;介绍如何制作视频游戏角色的毛绒动物。 该技术采用给定的角色 3D 模型及其纹理&#xff0c;并以编程方式生成缝纫图案。 虽然我已经编写了一般摘要并将源代码上传到 GitHub&#xff0c;但我在这里编写了对使这一…

【大数据面试知识点】Spark的DAGScheduler

Spark数据本地化是在哪个阶段计算首选位置的&#xff1f; 先看一下DAGScheduler的注释&#xff0c;可以看到DAGScheduler除了Stage和Task的划分外&#xff0c;还做了缓存的跟踪和首选运行位置的计算。 DAGScheduler注释&#xff1a; The high-level scheduling layer that i…

深度学习核心技术与实践之自然语言处理篇

非书中全部内容&#xff0c;只是写了些自认为有收获的部分。 自然语言处理简介 NLP的难点 &#xff08;1&#xff09;语言有很多复杂的情况&#xff0c;比如歧义、省略、指代、重复、更正、倒序、反语等 &#xff08;2&#xff09;歧义至少有如下几种&#xff1a; …

策略模式示例,Lambda表达式

这样会有很多代码冗余 以上代码使用策略模式优化 优化方案1 那么现在可以这样 优化方案二 原先定义了接口,还需要一个个写实现类,其实完全没必要,用匿名内部类方式就可以 优化方案三:用lambda方式简写 优化方案四:不需要定义接口 使用Stream API

从0到1浅析Redis服务器反弹Shell那些事

文章目录 前言Redis服务1.1 特点与应用1.2 安装与使用1.3 语法和配置1.4 未授权访问 反弹Shell2.1 Web服务写入Webshell2.2 Linux定时任务反弹shell2.3 /etc/profile.d->反弹shell2.4 写入ssh公钥登录服务器2.5 利用Redis主从复制RCE2.6 SSRF漏洞组合拳->RCE 总结 前言 …