Mybatis - MySQL - 枚举类型的映射

一直很好奇在 Java 类中定义的 枚举类型的属性通过 Mybatis 是怎么映射到 MySQL的.
于是做了一下尝试:

新建一个 Java 类
// 定义一个用户的枚举类
public class UserDTO{
	private String name;
	private GenderEnum gender;
}
// 定义一个性别的枚举类
public enum GenderEnum{
	MALE,FEMALE;
}
然后在 数据库中创建一张表
create table user(name varchar(255) primary key,gender varchar(255));
然后编写 mybatis 映射文件,并执行调用方法
<select id="select" resultType="com.example.demo23.model.User">
    select * from user;
</select>
调用该条 SQL ,并追踪代码

最后发现在 DefaultResultSetHandler 中会调用 EnumTypeHandler 去执行映射关系
在这里插入图片描述
在这里插入图片描述

然后调用 EnumTypeHandler 中的 getNullableResult 去实例化对应的属性值
在这里插入图片描述
在Mybatis映射中并不是直接的 MySQL 中字段的 枚举类型直接映射到 Java 中的枚举类型的,一方面由于 MySQL 的枚举类型在定义后具体枚举修改起来较为复杂,所以对应Java枚举可以映射为 MySQL 中的整型类型或者字符类型,麻烦的对象映射可以交由 Mybatis 去解决。

对于 Enum 类型 Mybatis 其实是对应的有两种处理器的,分别对应在数据库中存储的两种类型方式。当对于枚举数据的存储类型为varchar类型的时候,使用 EnumTypeHandler 进行获取枚举类型;当对于枚举数据的存储类型为整型类型如intbigint,smallint等类型时,使用 EnumOrdinalTypeHandler 进行处理枚举类型。

两种数据类型都可以使用,对于 varchar 类型,在查看数据时会更加直观一些,但会增加数据的使用空间并且增加索引的时间复杂度;对于整型类型,会方便通过数据创建索引,但是在直接从数据库查看数据时获取的结果会比较抽象。

  • EnumOrdinalTypeHandler 枚举序数方式处理器
  • EnumTypeHandler 枚举名称方式处理器
EnumOrdinalTypeHandler 整型类型(BIGINT,INT,SMALLINT) --> Java枚举

这种类型的枚举处理器会自动将数据库中保存为数值类型的字段映射为Java中对应的枚举类型。

映射逻辑:
当数据库中保存字段的值为 NULL 时,映射的枚举值为 null
反之,则根据具体的代码中枚举定义的顺序进行映射。

// org.apache.ibatis.type.EnumOrdinalTypeHandler#getNullableResult(java.sql.ResultSet, java.lang.String)
public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
  int ordinal = rs.getInt(columnName);
  // 判断表中字段值是否为NULL
  // ResultSet 会将部分 Null 值映射为0,所以还需要使用 wasNull 判断一下是否为 Null
  if (ordinal == 0 && rs.wasNull()) {
    return null;
  }
  // 根据枚举顺序映射,从0开始
  return toOrdinalEnum(ordinal);
}
// int 映射为 Enum ,超出索引的时候,抛出异常
private E toOrdinalEnum(int ordinal) {
  try {
    return enums[ordinal];
  } catch (Exception ex) {
    throw new IllegalArgumentException("Cannot convert " + ordinal + " to " + type.getSimpleName() + " by ordinal value.", ex);
  }
}
需要注意的问题

在数据库中保存Java 中的枚举值为数值类型需要注意一个问题,就是当我们在表中已经存在保存的枚举值后,修改 Java枚举类有可能导致映射顺序错误。

public enum Country{
	china,america;
}

如上所示,如果我已经按照上面的枚举类在数据库中保存了数据的话,那么 0 会被映射为 china1会被映射为 america。但如果我在这种情况下在枚举chinaamerica中间添加一个japan的话,那么新的映射关系就会是0会映射为china1会映射为japan2会映射为america,从而导致数据库中保存的数据异常。如果存在修改代码的情况为以防万一,最好还是保存Java枚举为数据库中的字符类型。

EnumTypeHandler 字符串(char,varchar,text)–> Java枚举

这种类型的枚举处理器会自动将数据库中字段类型为字符串类型(char,varchar,text)的字段值映射为Java枚举。
映射逻辑:
根据获取到的值,当值为 Null 时返回 null,否则,通过 Enum.valueOf()进行处理.

public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
  String s = rs.getString(columnName);
  // 当获取到的字段值为 Null 时返回 Null 否则通过 Enum.valueOf 实现映射
  // 当无法获取到映射值时,抛出异常
  return s == null ? null : Enum.valueOf(type, s);
}
总结

MySQL 中的varchar类型 映射为 Java 中的 Enum 类型时 ,会调用 Enum.valueOf() 方法进行转化,而 Enum.valueOf() 方法会在映射失败时抛出 IllegalArgumentException 异常.

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Mybatis-Plus中的枚举类主要有两种使用方式。第一种是通过使用@EnumValue注解来处理枚举类型。这种方式需要在实体属性上使用@EnumValue注解,并且在数据库中对应的字段上添加EnumValue注解,用于标识该字段为枚举类型的存储字段。示例代码如下所示: ```java public class User { // ... @EnumValue private AgeEnum age; // ... } public enum AgeEnum implements IEnum<Integer> { // ... } ``` 第二种方式是直接在实体属性中使用原生的枚举类型,并且在枚举类中使用@EnumValue注解来标识对应的数据库字段。示例代码如下所示: ```java public class User { // ... private GradeEnum grade; // ... } public enum GradeEnum { // ... @EnumValue GRADE_A(1), // ... } ``` 在配置方面,需要注意在扫描枚举包时,需要配置相关的扫描路径,以确保Mybatis-Plus能够正确地扫描到枚举类。具体的配置方式可以根据使用的框架进行相应的配置,例如在Spring Boot中可以参考如下的配置方式: ```java @Configuration public class MybatisPlusConfig { @Bean public ConfigurationCustomizer configurationCustomizer() { return configuration -> { // 扫描枚举包 configuration.getTypeHandlerRegistry().register("com.example.enums"); }; } } ``` 总之,Mybatis-Plus中的枚举类使用可以通过使用@EnumValue注解或者原生枚举类型配合@EnumValue注解来处理。在配置方面,需要确保正确配置枚举包的扫描路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值