SpringBoot-MyBatis - Java枚举类型 <---> MySQL Int,建立 类型处理器(typeHandlers)
场景:
MySQL里的某一个字段,比如:status状态,一共有5个状态,我们会在MySQL里 建立 status(int)字段,1、2、3、4、5 来标记5种状态;利用MyBatis在自动代码生成器生成实体类后,status会是integer类型;
而status 只有5种状态,且程序很多地方常用,于是我们建立status枚举,返回给终端的json里,也是返回枚举字符串,只是存MySQL里用int来存,节省空间,提升查询效率;好了多余的废话不说了,直接上代码:
1. 建立一个通用的枚举接口:
/**
* MySQL字段对应的枚举类需要实现这个接口
*/
public interface ISqlEnum {
/**
* 获取对应的MySQL里的值
*/
Integer getSqlInt();
}
2.定义一个枚举,实现枚举接口:
/**
* 平台类型,以后尽量使用这个来取代ShopType,枚举类;
* ShopType会等待合适的时机变更为:平台内部店铺类型如:专营店、自营店、旗舰店等
*/
public enum PlatformType implements ISqlEnum {
OFFLINE("线下", 9),
/**
* 淘宝/天猫
*/
TAOBAO("淘宝/天猫", 1),
/**
* 京东
*/
JINGDONG("京东", 2),
/**
* 拼多多
*/
PINDUODUO("拼多多", 3),
/**
* 抖音
*/
DOUYIN("抖音", 4),
/**
* 微信视频号
*/
WEIXIN("微信视频号", 5),
/**
* 阿里1688
*/
ALI1688("阿里1688", 6),
/**
* 快手
*/
KUAISHOU("快手", 7),
/**
* 苏宁
*/
SUNING("苏宁", 8);
/**
* 线下
*/
/**
* 店铺类型的英文名称就是枚举的小写,中文名称存储一下,方便直接返回给客户端;
*/
private String cnName;
/**
* MySQL里的int值
* 平台类型:1(淘宝),2(京东),3(拼多多),4(抖音),5(微信视频号),6(阿里1688),7(快手),8(苏宁),9(线下)
*/
private Integer sqlInt;
/**
* 私有构造方法
*/
private PlatformType(String cnName, Integer sqlInt) {
this.cnName = cnName;
this.sqlInt = sqlInt;
}
/**
* 对外公开获取中文名称的方法
*/
public String getCnName(){
return this.cnName;
}
@Override
public Integer getSqlInt() {
return this.sqlInt;
}
}
3. 定义一个类型处理器:类型处理器(typeHandlers),根据mybatis官方的文档,它默认已经有了2个枚举类型处理器:https://mybatis.net.cn/configuration.html#typeHandlers

A. EnumTypeHandler 这个官方默认的,通过官方的说明,源码得出结论:就是说 你MySQL里 若这个status字段是varchar类型,你向MySQL里存的是枚举的字符串的话,举例:PlatformType.TAOBAO,
你向MySQL里 存的是 TAOBAO 这个字符串的话,那么你可以直接在实体类里使用PlatformType枚举,而不用再做任何操作,因为TAOBAO这个字符串是可以直接与枚举类互转的;
B. EnumOrdinalTypeHandler 这个官方默认的,意思是:若你向MySQL里存的是枚举类的序号值,MySQL里是int 或兼容int的类型,也是不用做任何操作,在实体类里就可以使用 这个枚举;
因为序号也是可以直接与枚举互转的;
官方能做的也就A,B这2个了,其它的官方的也无能为力,A 首先不合适,正如官网所说,我们的DBA更倾向于枚举字段,在MySQL里用 int 类型来存储,节省空间,提升查询效率;
接下来说下B,B虽然MySQL里存的是int了,但是也太简陋了,只能按枚举的序号来,那么就意味着枚举类里的顺序 TAOBAO,JINGDONG,PDD你不能改变,一旦变成DOUYIN,TAOBAO,JINGDONG,PDD
则会出大乱子了!所以B还是简陋了,适合刚设计时就永远不会发生变化的枚举类;
细想你会发现官方能做的也只能这样了,因为枚举类是你自由定义的,要想 MySQL -- 枚举类,枚举类 --> Mysql;官方能做的就是 通过默认的字符串和 序号来转化,其它的转化是你自己自定义的,官方又如何能知道呢;

根据官方的提示,我们参考 官方默认的 两个枚举处理器,自定义一个我们自己的泛型枚举处理器;
public class SqlEnumHandler<E extends SqlEnum> extends BaseTypeHandler<E> {
/**
* 把枚举实例存入map,而不是官方的数组,因为数组查找的时候需要遍历,
* 官方使用数组是因为官方按枚举序号来的,即使使用数组也不需要遍历,
* 而我们不一定,sqlInt我们是自定义的,不是枚举实例的序号;
*/
private final Map<Integer, E> enumMap;
/**
* 官方的框架会自动调用这个方法,来构建枚举实例map
*/
public SqlEnumHandler(Class<E> type) {
if (type == null) {
throw new IllegalArgumentException("Type argument cannot be null");
}
//拿到类型实例,写入map
enumMap = new HashMap<>();
for (E enumConstant : type.getEnumConstants()) {
enumMap.put(enumConstant.getSqlInt(), enumConstant);
}
}
/**
* 1.若MySQL里的字段设置了不为Null,而你传入的枚举是Null,那么应该如何写入MySQL;(这个由你写代码决定,就是本方法)
* 2.若MySQL里的字段设置了可以为Null,而你传入的枚举也是Null,这种官方自动处理了,自动写入Null,不需要你写额外的代码;
* --------------------------------------------------------------
* 我们强制规定,若MySQL里一个字段是枚举,则这个字段【必须】设置成不为Null;
* 因为MySQL层面的问题,要在MySQL层面解决,举例:status都已经是一个枚举字段了,一共就5种状态,
* 是定死的,你非要搞成可以null,这就是你自己的脑袋有问题;我们这里不考虑Null的问题;
*/
@Override
public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
ps.setInt(i, parameter.getSqlInt());
}
/**
* 1.若MySQL里字段设置了可以为Null,当查询出来的结果为Null,你要转成哪个枚举实例;(需要你写代码来决定,就是本方法)
* 2.若MySQL里字段设置了可以为Null,查询出来的结果不为Null,这种的也需要你写代码来决定,就是本方法;
* -----------------------------
* 我们强制MySQL里的枚举字段不可以为Null,所以不考虑Null的问题,以下都是同理;
*/
@Override
public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
return enumMap.get(rs.getInt(columnName));
}
@Override
public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return enumMap.get(rs.getInt(columnIndex));
}
@Override
public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return enumMap.get(cs.getInt(columnIndex));
}
}
使用接口的话,也行,我们使用的是接口:
/**
* mybatis枚举类型处理器
*/
public class SqlEnumHandler<E extends SqlEnum> implements TypeHandler<E> {
/**
* 把枚举实例存入Map
*/
private final Map<Integer, E> enumMap;
/**
* 根据枚举类型构建Map
*/
public SqlEnumHandler(Class<E> type) {
if (type == null) {
throw new IllegalArgumentException("Type argument cannot be null");
}
//拿到类型实例,写入map
enumMap = new HashMap<>();
for (E enumConstant : type.getEnumConstants()) {
enumMap.put(enumConstant.getSqlInt(), enumConstant);
}
}
/**
* Java枚举 ---写入---> MySQL Int
*/
@Override
public void setParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
ps.setInt(i, parameter.getSqlInt());
}
/**
* MySQL Int ---读取---> Java枚举
* 强制规定:此MySQL字段必须设置成不为Null,因为MySQL层面的问题,要在MySQL层面解决,
* 举例:status都已经是一个枚举字段了,一共就5种状态,是定死的,若MySQL里允许为Null,
* 这就是开发者有问题,需要去修复MySQL,而不是在这里处理Null;这里不考虑Null的问题;
*/
@Override
public E getResult(ResultSet rs, String columnName) throws SQLException {
return enumMap.get(rs.getInt(columnName));
}
@Override
public E getResult(ResultSet rs, int columnIndex) throws SQLException {
return enumMap.get(rs.getInt(columnIndex));
}
@Override
public E getResult(CallableStatement cs, int columnIndex) throws SQLException {
return enumMap.get(cs.getInt(columnIndex));
}
}
4. spring boot 的 application.properties 加上配置,配置一下枚举类型处理器,你会发现spring boot 会有这个配置,原因是为什么呢,肯定是mybatis官方也知道他提供的那2个枚举类型处理器,弱爆了,
而这个处理器,只能由用户自己来编写代码,所以他有一个配置来让你指定;
#你指定一下你自己写的那个SqlEnumHandler类就行了;
mybatis.configuration.default-enum-type-handler
================================
以上4步搞定后,就可以了,测试:




SpringBoot-MyBatis - Java枚举类型 <---> MySQL Int,建立 类型处理器(typeHandlers)的更多相关文章
- java中存储mysql数据库时间类型
Mysql 与 java 的时间类型 MySql的时间类型有 Java中与之对应的时间类型 date java.sql.Date Datetime ...
- springboot mybatis自定义枚举enum转换
原文链接:https://blog.csdn.net/u014527058/article/details/62883573 一.概述 在利用Spring进行Web后台开发时,经常会遇到枚举类型的绑定 ...
- springboot+mybatis集成多数据源MySQL/Oracle/SqlServer
日常开发中可能时常会遇到一些这样的需求,业务数据库和第三方数据库,两个或多个数据库属于不同数据库厂商,这时候就需要通过配置来实现对数据库实现多源处理.大致说一下我的业务场景,框架本身是配置的sprin ...
- mysql int 整数类型 解释显示宽度 和 存储宽度
存储宽度 是实际存储记录宽度 存储宽度默认是写死的,就算修改宽度也改变不了,改变的是显示宽度 ============有符号和无符号int============= 创建一个 无符号的 int 整数类 ...
- spring boot1.1 idea + springboot + mybatis(mybatis-generator) +mysql +html实现简单的登录注册
前言 这两年springboot比较火,而我平时的工作中不怎么使用spring boot,所以工作之余就自己写写项目练练手,也跟大家一起学习. 打算从最开始的搭架子,登录注册,到后台管理的增删改查,业 ...
- springboot + mybatis 支持oracle和mysql切换含源码
1.springboot 启动类加入bean 如下 // DatabaseIdProvider元素主要是为了支持不同的数据库@Beanpublic DatabaseIdProvider getData ...
- java中存储mysql数据库时间类型【date、time、datetime、timestamp】
在MySQL中对于时间的存储自己见表的时候都是设置的varchar类型的,感觉挺方便的. 昨天拿别人建好的表写代码,发现这张表中时间类型为datetime的,凭感觉试了一下不行,网上查了刚开始试了好几 ...
- 将String类型转换为int整数类型
示例如下: public class demo { public static void main(String[] args) { String s="10"; 6 7 //St ...
- MyBatis(八):Mybatis Java API枚举类型转化的用法
最近工作中用到了mybatis的Java API方式进行开发,顺便也整理下该功能的用法,接下来会针对基本部分进行学习: 1)Java API处理一对多.多对一的用法: 2)增.删.改.查的用法: 3) ...
- 扩展mybatis和通用mapper,支持mysql的geometry类型字段
因项目中需要用到地理位置信息的存储.查询.计算等,经过研究决定使用mysql(5.7版本)数据库的geometry类型字段来保存地理位置坐标,使用虚拟列(Virtual Generated Colum ...
随机推荐
- mybatis-plus Date类型的参数 只有年月日 没有时分秒的解决办法
问题: 使用mybatis-plus 设计实体的时候 使用 Date inTime; 数据库里的时间2021-11-05 22:00:13 但java里的时间变成了2021-11-05 00: ...
- Jensen 不等式证明
Jensen 不等式定义 若 \(f(x)\) 为区间 \(I\) 上的下凸函数,则对于任意 \(x_{i} \in I\) 和满足 \(\displaystyle\sum_{i=1}^{n} \la ...
- Kubernetes APIServer 最佳实践
1. kubernetes 整体架构 kubernetes 由 master 节点和工作节点组成.其中,master 节点的组件有 APIServer,scheduler 和 controller-m ...
- kafka 在 zookeeper 中保存的数据内容
转载请注明出处: 1. 服务器上下载 kafka : wget https://archive.apache.org/dist/kafka/2.4.0/kafka_2.12-3.2.0.tgz 2. ...
- maven总结三: 常用插件
本文为博主原创,转载请注明出处: 目录: 1. maven-release-plugin 2. maven-compiler-plugin 3. maven-assembly-plugin 4. sp ...
- Git-远程仓库-remote-pull-push
- [转帖]nginx 剖析 request_time和upstream_response_time的误区、区别
https://cloud.tencent.com/developer/article/1767981 首先,澄清一个误区 upstream_response_time必须在upstream配置时才能 ...
- [转帖]Linux Shell编程 循环语法
https://zhuanlan.zhihu.com/ for循环 for 循环是固定循环,也就是在循环时已经知道需要进行几次循环.有时也把 for 循环称为计数循环.语法: for 变量 in 值1 ...
- [转帖]优化命令之iotop命令
文章目录 引言 一.iotop简介 1.iotop安装 2.iotop语法 3.iotop参数 二.I/O的常用快捷键 三.交互模式 四.iotop示例 1.只显示正在产生I/O的进程 2.显示指定P ...
- [转帖]Linux 学习笔记: shell中${} 的用法,删除&替换
Linux 学习笔记: shell中${} 的用法,删除&替换 字符串的删除 echo${i##*/} 删除 / 前的所有内容 ## 删除 tt=$i echo{tt:22} #取的22位以后 ...