场景:

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)的更多相关文章

  1. java中存储mysql数据库时间类型

    Mysql 与 java 的时间类型 MySql的时间类型有 Java中与之对应的时间类型   date                 java.sql.Date   Datetime        ...

  2. springboot mybatis自定义枚举enum转换

    原文链接:https://blog.csdn.net/u014527058/article/details/62883573 一.概述 在利用Spring进行Web后台开发时,经常会遇到枚举类型的绑定 ...

  3. springboot+mybatis集成多数据源MySQL/Oracle/SqlServer

    日常开发中可能时常会遇到一些这样的需求,业务数据库和第三方数据库,两个或多个数据库属于不同数据库厂商,这时候就需要通过配置来实现对数据库实现多源处理.大致说一下我的业务场景,框架本身是配置的sprin ...

  4. mysql int 整数类型 解释显示宽度 和 存储宽度

    存储宽度 是实际存储记录宽度 存储宽度默认是写死的,就算修改宽度也改变不了,改变的是显示宽度 ============有符号和无符号int============= 创建一个 无符号的 int 整数类 ...

  5. spring boot1.1 idea + springboot + mybatis(mybatis-generator) +mysql +html实现简单的登录注册

    前言 这两年springboot比较火,而我平时的工作中不怎么使用spring boot,所以工作之余就自己写写项目练练手,也跟大家一起学习. 打算从最开始的搭架子,登录注册,到后台管理的增删改查,业 ...

  6. springboot + mybatis 支持oracle和mysql切换含源码

    1.springboot 启动类加入bean 如下 // DatabaseIdProvider元素主要是为了支持不同的数据库@Beanpublic DatabaseIdProvider getData ...

  7. java中存储mysql数据库时间类型【date、time、datetime、timestamp】

    在MySQL中对于时间的存储自己见表的时候都是设置的varchar类型的,感觉挺方便的. 昨天拿别人建好的表写代码,发现这张表中时间类型为datetime的,凭感觉试了一下不行,网上查了刚开始试了好几 ...

  8. 将String类型转换为int整数类型

    示例如下: public class demo { public static void main(String[] args) { String s="10"; 6 7 //St ...

  9. MyBatis(八):Mybatis Java API枚举类型转化的用法

    最近工作中用到了mybatis的Java API方式进行开发,顺便也整理下该功能的用法,接下来会针对基本部分进行学习: 1)Java API处理一对多.多对一的用法: 2)增.删.改.查的用法: 3) ...

  10. 扩展mybatis和通用mapper,支持mysql的geometry类型字段

    因项目中需要用到地理位置信息的存储.查询.计算等,经过研究决定使用mysql(5.7版本)数据库的geometry类型字段来保存地理位置坐标,使用虚拟列(Virtual Generated Colum ...

随机推荐

  1. 本地存储sessionStorage、localStorage

    本地存储特性 数据存储在用户浏览器中 设置.读取方便.甚至页面刷新不丢失数据 容量较大,sessionStorage约5M.localStorage约20M 只能存储字符串,可以将对象JSON.str ...

  2. java基础(3)--pulic class与class的区别

    1.一个类前面的public是可有可无的2.如果一个类使用 public 修饰,则文件名必须与类名一致3.如果一个类前面没有使用public修饰,则文件名可以与类名不一致.当编译成功后会生成对应类名的 ...

  3. node pressure and pod eviction

    0. overview There are too many guides about node pressure and pod eviction, most of them are specifi ...

  4. Kubernetes APIServer 最佳实践

    1. kubernetes 整体架构 kubernetes 由 master 节点和工作节点组成.其中,master 节点的组件有 APIServer,scheduler 和 controller-m ...

  5. UPF - Power Intent Basic

    Mainstream Low Power techniques Low Vth - 阈值电压比较低,翻转时间小,漏电流比较大,功耗大,速度快 High Vth - 阈值电压比较高,翻转时间长,漏电流比 ...

  6. 12-异步FIFO

    1.异步FIFO的应用 跨时钟域 批量数据 传输效率高 2.异步FIFO结构 FIFO深度 - 双端口RAM设计 3.异步FIFO深度计算 4.异步FIFO读写地址的编码 5.异步FIFO读写时钟域的 ...

  7. 【C/C++】 开发必备知识总结

    >from: C/C++ 开发必备知识总结 (qq.com) const 作用 修饰变量,说明该变量不可以被改变: 修饰指针,分为指向常量的指针和指针常量: 常量引用,经常用于形参类型,即避免了 ...

  8. 2023 SHCTF-校外赛道 PWN WP

    WEEK1 nc 连接靶机直接梭 hard nc 同样是nc直接连,但是出题人利用linux命令的特性,将部分flag放在了特殊文件中 利用ls -a查看所有文件,查看.gift,可以得到前半段 然后 ...

  9. win11不改时区,安装 android 子系统,运行android app

    win11开启虚拟机平台 下载安卓子系统 打开https://store.rg-adguard.net , 在URL中输入:https://www.microsoft.com/store/produc ...

  10. [转帖]Linux 下rsync命令详细整理

    https://blog.csdn.net/weixin_44052462/article/details/116134761 rsync是一个功能非常强大的工具,其命令也有很多功能特色选项,我们下面 ...