MybatisPlus支持Entity里使用枚举做为属性类型的源码解析

别再踩坑了!MyBatisPlus更新字段为null的三种正确写法(附LambdaUpdateWrapper源码浅析) 本文详细解析了MyBatisPlus更新字段为NULL的三种正确写法,重点推荐使用LambdaUpdateWrapper实现类型安全的字段置空操作。通过源码浅析揭示Lambda表达式转换为SQL的底层机制,并提供性能优化建议和版本兼容性指南,帮助开发者避免常见坑点,提升数据库操作效率。 阅读详情

前几天同事提的一个疑问,为啥能这么用?由于我也没这么用过,于是带着好奇心去探索了一下并整理了此文章。


场景


枚举类:

@Getter
@AllArgsConstructor
public enum PublishStatus {
    PUBLISHED(1, "已发布"), CANCEL(2, "已取消"), DELETED(3, "已删除");
    
    @EnumValue
    private final int code;
    private String name;
}

Entity实体类:

public class PublishInfo implements Serializable {

    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

	private String name;

    private PublishStatus status; //枚举类型

在Service里查询DB数据,如果表里这行记录的status=1,那么映射成Entity的status属性如下:
在这里插入图片描述


实现条件

1.mybatis-plus配置里指定枚举路径;

mybatis-plus:
  type-enums-package: com.xxx.xxx.enums
  mapper-locations: classpath*:mapper/**/*.xml

2.枚举类里使用@EnumValue注解标记要映射的枚举属性,如上。


3.Entity里使用该枚举做为属性类型,如上。


源码解析

这里只贴关键代码

public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {

    @Override
    public void afterPropertiesSet() throws Exception {
        notNull(dataSource, "Property 'dataSource' is required");
        state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
            "Property 'configuration' and 'configLocation' can not specified with together");

        this.sqlSessionFactory = buildSqlSessionFactory();
    }

    protected SqlSessionFactory buildSqlSessionFactory() throws Exception {

        // TODO 自定义枚举类扫描处理
        if (hasLength(this.typeEnumsPackage)) {
            
            // 取得类型转换注册器
            TypeHandlerRegistry typeHandlerRegistry = targetConfiguration.getTypeHandlerRegistry();
            classes.stream()
                .filter(Class::isEnum)
                .filter(MybatisEnumTypeHandler::isMpEnums)
                .forEach(cls -> typeHandlerRegistry.register(cls, MybatisEnumTypeHandler.class));
        }

        return sqlSessionFactory;
    }

扫描配置的枚举路径下所有class文件,并MybatisEnumTypeHandler::isMpEnums匹配是否有@EnumValue注解:

@Deprecated
public class MybatisEnumTypeHandler<E extends Enum<?>> extends BaseTypeHandler<Enum<?>> {
   /**
     * 判断是否为MP枚举处理
     *
     * @param clazz class
     * @return 是否为MP枚举处理
     * @since 3.3.1
     */
    public static boolean isMpEnums(Class<?> clazz) {
        return clazz != null && clazz.isEnum() && (IEnum.class.isAssignableFrom(clazz) || findEnumValueFieldName(clazz).isPresent());
    }

   /**
     * 查找标记标记EnumValue字段
     *
     * @param clazz class
     * @return EnumValue字段
     * @since 3.3.1
     */
    public static Optional<String> findEnumValueFieldName(Class<?> clazz) {
        if (clazz != null && clazz.isEnum()) {
            String className = clazz.getName();
            return Optional.ofNullable(CollectionUtils.computeIfAbsent(TABLE_METHOD_OF_ENUM_TYPES, className, key -> {
                Optional<Field> optional = Arrays.stream(clazz.getDeclaredFields())
                    .filter(field -> field.isAnnotationPresent(EnumValue.class))
                    .findFirst();
                return optional.map(Field::getName).orElse(null);
            }));
        }
        return Optional.empty();
    }

能匹配到的枚举类,会注册到TypeHandlerRegistry。

typeHandlerRegistry.register(cls, MybatisEnumTypeHandler.class)

注册的过程中,有一个关键代码 “c.newInstance(javaTypeClass)”,即MybatisEnumTypeHandler实例化时构造方法里传入了当前枚举类。

public <T> TypeHandler<T> getInstance(Class<?> javaTypeClass, Class<?> typeHandlerClass) {
    if (javaTypeClass != null) {
      try {
        Constructor<?> c = typeHandlerClass.getConstructor(Class.class);
        return (TypeHandler<T>) c.newInstance(javaTypeClass);
      } catch (NoSuchMethodException ignored) {
        // ignored
      } catch (Exception e) {
        throw new TypeException("Failed invoking constructor for handler " + typeHandlerClass, e);
      }
    }
    try {
      Constructor<?> c = typeHandlerClass.getConstructor();
      return (TypeHandler<T>) c.newInstance();
    } catch (Exception e) {
      throw new TypeException("Unable to find a usable constructor for " + typeHandlerClass, e);
    }
  }

来看看MybatisEnumTypeHandler的构造方法:

public MybatisEnumTypeHandler(Class<E> type) {
        if (type == null) {
            throw new IllegalArgumentException("Type argument cannot be null");
        }
        this.type = type;
        MetaClass metaClass = MetaClass.forClass(type, REFLECTOR_FACTORY);
        String name = "value";
        if (!IEnum.class.isAssignableFrom(type)) {
            name = findEnumValueFieldName(this.type).orElseThrow(() -> new IllegalArgumentException(String.format("Could not find @EnumValue in Class: %s.", this.type.getName())));
        }
        this.invoker = metaClass.getGetInvoker(name);
    }

通过findEnumValueFieldName()方法获取@EnumValue注解标记要映射的枚举属性,结合上面场景name就等于枚举类PublishStatus的code属性。然后拿到MethodInvoder,结合上面场景,this.invoker等于枚举类PublishStatus的getCode()方法。


每次映射拿值时,就通过构造方法里赋值的this.invoker的invoke()方法,即枚举类PublishStatus的getCode()方法拿值。

   private Object getValue(Object object) {
        try {
            return invoker.invoke(object, new Object[0]);
        } catch (ReflectiveOperationException e) {
            throw ExceptionUtils.mpe(e);
        }
    }

Mybatis填充属性值时,getValue()方法就能拿到 枚举类里对应的值了,并赋值给Entity属性值。

  @Override
  public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
    setNonNullParameter(ps, i, parameter, jdbcType);
  }
  
   @Override
   public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType)
        throws SQLException {
        if (jdbcType == null) {
            ps.setObject(i, this.getValue(parameter));
        } else {
            // see r3589
            ps.setObject(i, this.getValue(parameter), jdbcType.TYPE_CODE);
        }
   }

MyBatis-Plus雪花算法深度解析:原理、配置与实战避坑指南 在分布式系统架构中,生成全局唯一标识符(ID)是确保数据一致性与系统可扩展性的基础需求。传统数据库自增ID在分库分表和高并发场景下存在瓶颈,因此分布式ID生成方案应运而生。雪花算法(Snowflake)作为一种经典的分布式ID生成器,其核心原理是将时间戳、工作机器ID和序列号组合成一个64位长整型,实现了高性能、大致有序且全局唯一的ID生成。该技术方案在微服务与分布式架构中具有重要价值,能有效支持高并发写入、数据分片及合并等场景。本文聚焦于在MyBatis-Plus框架中集成与优化雪花算法,深入探讨其配置细 阅读详情

相关推荐

SpringBoot箱包存储系统:从业务建模到仓储管理实战

在软件开发领域,业务建模与数据库设计是构建企业级应用的核心基础。其原理在于将现实世界的业务实体与流程抽象为数据模型,通过合理的表结构设计确保数据一致性与完整性。这一技术的价值在于能够支撑复杂的业务规则与状态流转,是实现高效数据管理的关键。在仓储管理、库存追踪等应用场景中,业务建模尤为重要。本文以箱包存储系统为例,深入探讨如何将仓储管理的业务需求转化为技术实现,涵盖从实体类设计到事务管理的完整流程,并详细解析如何使用MyBatis-Plus进行高效数据操作,以及通过Thymeleaf实现前后端交互,为开发者提

weixin_30781433的博客 304

MyBatis 中,如何使用枚举类型?

需要注意的是,使用 EnumTypeHandler 时,需要确保枚举类型对应的值存在于枚举类型中,否则可能会抛出异常。在使用 MyBatis 进行查询时,如果数据库中的列名与 Java 实体类中的属性名不一致,就会出现字段名和实体类属性名不一致的问题。MyBatis 支持 Java 中的枚举类型,可以将枚举类型与数据库中存储的值相互映射,从而方便地进行数据查询、增加、修改和删除等操作。这样,MyBatis 会将查询结果中的列名映射到 Java 实体类中的属性名,就可以直接使用实体类进行操作。

luoluoal的博客 5756

SpringBoot+Vue全栈项目实战:大学生心理咨询平台开发指南

前后端分离架构是现代Web应用开发的主流模式,其核心在于通过定义清晰的API契约,实现前端与后端的解耦与并行开发。该架构基于RESTful API设计规范,后端专注于业务逻辑与数据持久化,前端则负责用户交互与界面渲染,两者通过HTTP协议和JSON数据格式进行通信。这种模式的技术价值在于提升了开发效率、增强了系统的可维护性和可扩展性,并使得团队协作更加清晰。在实际工程实践中,SpringBoot作为后端开发的“事实标准”,以其约定大于配置的理念简化了项目搭建;而Vue.js作为渐进式前端框架,通过响应式数据

weixin_34279246的博客 386

Entity中使用枚举字段

数据库中一些状态字段通常用0,1,2或者简单的字符串进行维护,然后JavaBean实体类中用枚举类型来保存,这样做便于使用和维护。easymybatis上使用枚举属性很简单:枚举类实现net.oschina.durcframework.easymybatis.handler.BaseEnum接口即可。下面是具体例子:第一步public enum UserInfoType implements Bas

axe的专栏 7716

基于SpringBoot的校园二手交易平台:从零搭建与毕设实战指南

在Java Web开发领域,SpringBoot作为一款主流的快速应用开发框架,因其简化配置和强大的生态支持,已成为构建企业级应用的首选。其核心原理在于通过自动配置和起步依赖,极大降低了项目搭建的复杂度,使开发者能聚焦于业务逻辑实现。这一技术价值在快速原型开发和教学实践中尤为突出,特别适用于校园二手交易平台这类具有典型增删改查业务场景的系统。通过整合MyBatis-Plus实现高效数据持久化,并利用Thymeleaf模板引擎进行页面渲染,开发者可以快速构建出功能完整、架构清晰的应用。本文将以一个开箱即用的高

cunfuteng7334的博客 356

Java+Vue+Spring Boot+MySQL校园社团管理系统毕业设计全栈开发指南

Web应用开发的核心在于构建一个结构清晰、可维护且能有效解决实际问题的系统。其基本原理通常遵循前后端分离的架构模式,后端负责业务逻辑与数据持久化,前端负责用户交互与数据展示。这种架构的价值在于提升了开发效率、便于团队协作,并增强了系统的可扩展性。在实际应用中,一个典型的场景是校园信息化建设,例如开发一个校园社团信息管理系统。这类系统需要处理用户、社团、活动等多实体间的复杂关系,这正是关系型数据库和MVC框架的用武之地。本文将以Java和Vue为核心技术栈,深入探讨如何从零构建一个功能完整的校园社团管理系统。

weixin_33857679的博客 342

MybatisPlus中Enum的使用(MybatisEnumTypeHandler)及遇到的问题

下面是TypeHandlerRegistry部分代码,其中javaTypeClass会根据是否配置javaType进行变化,如果javaType=true,那会按照实体类或者xml对应字段的java类型获取,如果javaType=false,那这里有可能是Object或者null,对于MybatisEnumTypeHandler来说应该是Object(我调试的时候是这样)上面的第三步不用了,然后又分两种情况,BaseMapper方式和Mapper.xml方式,其实主要是看你的sql语句在哪。...

yiyuzz的博客 9164

SpringBoot+Vue前后端分离心理健康测评系统实战开发指南

前后端分离架构是现代Web应用开发的主流模式,其核心思想是将用户界面(前端)与业务逻辑和数据(后端)解耦,通过API进行通信。这种架构模式提升了开发效率、可维护性和团队协作能力。在技术实现上,SpringBoot作为后端框架,提供了快速构建RESTful API的能力,而Vue.js则以其响应式和组件化的特性,成为构建动态前端界面的热门选择。结合JWT(JSON Web Token)实现安全的用户认证与授权,是保障系统安全性的关键技术。这些技术的组合,在需要高效数据处理和良好用户体验的应用场景中,如在线测评

weixin_34269583的博客 422

Mybatis-plus使用枚举类型定义属性映射数据库

在业务种常常会出现数据库内的字段是char类型,然后需要判断类型返回给前端 例如数据库 0表示性别为男,1表示性别为女,然后Entity实体类内通过Integer进行映射,然后再返回给前端时通常需要判断后再返回,这样不但闲的很臃肿,也布不利于维护,因此我们可以使用Mybatis-Plus的提供的枚举功能去解决这种场景 1:创建枚举类型 public enum UserSexEnum { Male("男","m"), Female("女","f"), Other("其他","n");

爱码猿的博客 7433

关于MyBatis-Plus 如何在实体类上使用@EnumValue注解?

通过使用@EnumValue注解,我们可以方便地在实体类中使用枚举类型,并在数据库中存储枚举的值。本文提供了一个详细的示例,展示了如何在实体类上使用@EnumValue注解。希望对你理解MyBatis-Plus的枚举类型处理有所帮助!

理论都是虚的,代码才是王道。 1495

Audio2Face进阶玩法:结合LiveLink在UE5中实现MetaHuman全身动画+语音驱动(保姆级配置指南)

本文提供了一份详尽的保姆级教程,指导如何将NVIDIA Audio2Face与Unreal Engine 5的LiveLink功能结合,实现驱动MetaHuman数字人面部表情的同时,无缝融合身体动画。文章详细讲解了从环境准备、插件部署、基础面部驱动测试,到动画蓝图高级配置与多数据流融合的全流程,并分享了性能优化与问题排查的实战经验,旨在帮助创作者打造表情与肢体动作协调统一的生动数字人。

q9w8e7r6t5的博客 197

mybatiplus的apply_MyBatis-Plus | 最优雅最简洁地完成数据库操作

引言两点:一,使用MyBatis-Plus最新版(3.0.1)完成相关操作二,好久没写MyBatis操作数据库的博文了,有没有想我啊,哈哈,认真看,认真听,认真学。测试效果:下面听我细细道来,MyBatis-Plus的优雅、简洁与强大。代码生成器代码生成器,又被叫做逆向工程,MyBatis官方为了推广,自己也写了一个,我之前也使用这个,功能也是非常强大,强大以为支持自定义配置,那么问题来了,我该怎...

weixin_39940957的博客 724

提示deepseek生成完整的json用于对接外部API

通过精准的提示词设计(字段过滤、格式约束)、动态验证机制(自检与修正)和官方模板参考,可有效确保DeepSeek生成的JSON纯净无冗余。

神棍之路 2309

MyBatis-Plus代码生成器实战:从原理到配置,一键生成CRUD代码

在Java企业级开发中,ORM框架是连接数据库与业务逻辑的关键组件,它通过对象关系映射原理,将数据库表结构映射为Java对象,简化了数据持久化操作。MyBatis作为一款流行的半自动化ORM框架,提供了灵活的SQL编写能力,而MyBatis-Plus在其基础上增强了通用CRUD操作,进一步提升了开发效率。其核心价值在于通过代码生成器自动化生成基础数据访问层代码,将开发者从重复的实体类、Mapper接口和XML文件编写中解放出来,实现标准化与工程化。这一技术特别适用于快速构建后台管理系统、微服务数据层等需要大

weixin_34238633的博客 456

nsight-system教程

参考nsight-compute使用教程-优快云博客。

youzjuer的博客 1894

42、使用mmrotate中k3det进行旋转目标检测,并进行mnn部署和ncnn部署

基本思想:仍然是身份证分割,并进行ncnn和mnn的c++的部署开发

sxj731533730 5711

每周小记——SpringBoot&Mybatis-Plus

本文概述SpringBoot实践及整合MyBatis-Plus与Swagger,涵盖基础配置(环境搭建、YAML、多环境部署、热部署),框架整合(Swagger3自动API文档、MyBatis-Plus简化CRUD/逻辑删除/乐观锁/代码生成器/多数据源),高级特性(YAML封装、函数式接口、ActiveRecord模式),实用技巧(自定义Banner、分页/自定义SQL、枚举处理、Service封装),以代码示例驱动企业级开发。

weixin_57655687的博客 2393

Pytorch中安装 torch_geometric 详细图文操作(全)

如果已经安装了pytorch版本,对应跳过步骤一,直接安装步骤二即可注意:依赖包的配置需要根据pytorch版本号以及cuda的版本号,版本号要适配,否则部分函数无法使用。

码农研究僧的博客 3448

SpringBoot社区网格化管理平台:从零构建完整Java Web项目实战

SpringBoot作为Java领域主流的Web应用开发框架,以其自动配置、快速启动和简化部署的特性,极大地提升了后端服务的开发效率。其核心原理在于通过约定大于配置的理念,整合Spring生态,让开发者能专注于业务逻辑的实现。在工程实践中,结合MyBatis-Plus进行数据持久化操作,能高效完成对社区网格化管理这类业务系统中**用户管理、事件上报**等核心模块的CRUD与复杂查询。这类技术组合的价值在于,能够快速构建出具备清晰分层架构(Controller-Service-Mapper)和完整业务流程的现

weixin_34161064的博客 461

数学建模算法案例精讲500篇-【深度强化学习】深度确定性策略梯度(DDPG)(附MATLAB和python代码实现)

它是一种学习连续动作的无模型策略算法。它结合了DPG(确定性策略梯度)和DQN(深度Q网络)的思想。它利用DQN中的经验重放和延迟更新的目标网络,并基于DPG,可以在连续的动作空间上运行。# 用于生成带有噪声的动作def __init__(self, action_space, mu=0.0, theta = 0.15, max_sigma = 0.3, min_sigma = 0.3, decay_period = 100000):#decay_period要根据迭代次数合理设置# 均值 mu。

qq_36130719的博客 325

6.Burp Suite 入门篇 —— Burp Scanner 漏洞扫描

Burp Scanner 既可以是独立的全自动扫描器,也可以在手动测试中当作强大的辅助手段,而且随着技术改进,Burp Scanner 能检测到的漏洞数量也在不断增加。Burp Scanner 功能只在 burpsuite 专业版和企业版中里有,本篇教程讲的是专业版的 Burp Scanner 用法。

YouTheFreedom的博客 1万+

Spring Boot+Vue 3酒店管理系统实战:从零构建前后端分离项目

在软件开发领域,前后端分离架构已成为构建现代Web应用的主流模式,其核心在于通过RESTful API实现前后端职责解耦,提升开发效率和系统可维护性。这一架构模式的技术价值在于,它允许前端专注于用户界面与交互逻辑,后端则聚焦于业务处理与数据持久化,两者可独立开发、部署与扩展。在众多应用场景中,企业级管理系统是检验前后端分离技术栈综合运用能力的典型实战场景。本文以酒店管理系统为例,深入探讨如何将Spring Boot的自动配置、MyBatis-Plus的高效数据操作、Vue 3的组合式API以及Element

weixin_33937499的博客 416

机器学习实战26-一种基于LightGBM的股市涨跌预测系统与代码实现过程

在全球经济一体化的背景下,股市作为经济活动的晴雨表,其波动与预测对于投资者、金融机构乃至国家政策制定者而言至关重要。随着金融市场的日益复杂化与信息量的爆炸式增长,股市分析不再仅限于基本面和技术面的传统研究,而是迫切需要更加精准、高效及智能化的方法来捕捉市场动态,以辅助决策制定。模型评估是确保LightGBM股市预测系统准确性和稳定性不可或缺的一环。通过综合运用多种评估指标、科学的验证方法以及深入的性能分析,我们不仅能够全面理解模型的能力和限制,还能为持续优化模型、提升预测准确性奠定坚实基础。

微学AI的博客 2328

SpringBoot酒店客房管理系统实战:从零搭建完整Java Web项目

在Java Web开发领域,SpringBoot作为主流框架,以其简化配置和快速开发的特性,极大地提升了后端应用的构建效率。其核心原理在于通过约定大于配置和自动装配机制,整合了Spring生态,降低了开发复杂度。这种技术价值在于能让开发者更专注于业务逻辑的实现,而非繁琐的环境搭建。在典型的应用场景中,如酒店客房管理系统,SpringBoot常与MyBatis-Plus、Thymeleaf等技术栈协同,构建功能完整的管理后台。本文聚焦于一个基于SpringBoot的实战项目,深入解析如何将客房预订、入住退房等

weixin_30240349的博客 355

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Mapper.map 对象转换工具类完整指南:从原理到实践

Mapper.map 对象转换工具类完整指南:从原理到实践

北执南念的博客 726

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

SpringBoot应用代码保护实战:从ProGuard混淆到字节码加密

在Java应用开发中,代码保护是保障知识产权和提升应用安全性的重要环节。其核心原理在于通过技术手段增加反编译和逆向工程的难度,从而保护核心业务逻辑与敏感信息。对于广泛使用的SpringBoot框架应用,代码保护的技术价值尤为突出,它能有效防止核心算法、配置信息及业务规则在交付或部署后遭到泄露与恶意利用。在实际工程实践中,开发者常面临在便捷性、性能与安全性之间的权衡。常见的应用场景包括商业软件交付、部署于不受控环境、以及保护包含敏感处理逻辑的微服务等。本文聚焦于SpringBoot程序的代码保护,深入探讨了以

congsikuai0611的博客 402
上一篇: Spring启动时实现初始化的几种方式
下一篇: SpringCould Gateway里添加前置过滤器校验参数格式
pbxs
博客等级 码龄14年 94粉丝 62原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值