Hibernate中枚举Enum类型的映射策略

2023-11-01

在Java中Enum是一种“奇葩”的存在,“奇葩”不代表没用,对于这种比较特殊的存在,hibernate会有很多种选择来完成Enum类型字段的映射,首先要说明的是在hibernate都是把Enum类型的字段映射成基本类型的字段,并且我这里不使用任何配置文件来配置映射,而是统一使用注解这种方式来完成映射。

注意本文使用的数据库是MySQL5.7,版本和数据库类型可能会有不同的结果。

首先我们要明确的是将Enum类型的字段映射到数据库中有两种方式:

  1. 一个是通过使用Enum类型实例在Enum中声明的顺序,也就是ordinal属性,通过这个序号来将Enum类型字段映射成int类型来存储;
  2. 一个是通过使用Enum类型实例中的name属性来完成映射,这里讲Enum类型映射成String类型来完成存储;

这两个属性其实都在java.lang.Enum中,这个类是所有Enum类型的父类。

1. 不使用任何注解

当不使用任何注解的时候,默认情况下是使用ordinal属性,也就是Enum类型实例在Enum中声明的顺序来完成映射的,具体情况如下:

@Entity
public class Person implements Serializable{
    private static final long serialVersionUID = 8849870114127659929L;

    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column
    private Gender gender;

    public Person(String name, Gender gender){
        this.name = name;
        this.gender = gender;
    }

    // getter、setter
}

这里Gender就是我们的Enum类,如下:

public enum Gender {
    male("男"),
    female("女");

    private String name;
    private Gender(String name){
        this.name = name;
    }

    public String getName(){
        return this.name;
    }
}

此时看到生成的表结构如下:

这里可以看出Enum类型字段Gender**被映射成int(11)类型**,通过往里面插入一条数据看一下结果,如下:

@Test
public void testJpa(){
    personService.save(new Person("Jhon", Gender.male));
    personService.save(new Person("Lily", Gender.female));
}

上边向数据库中插入了两条记录,personService是操作数据库的service,结果如下:

可以看出Gender.male对应的序号是0,Gender.female对应的是1,可以看出在使用ordinal属性映射时的序号是从0开始的

2. 使用@Enumerated注解

注解javax.persistence.Enumerated从名字上来看就可以明白是为了映射Enum类型的,从它的javadoc文档中可以说明:

Specifies that a persistent property or field should be persisted as a enumerated type. The Enumerated annotation may be used in conjunction with the Basic annotation, or in conjunction with the ElementCollection annotation when the element collection value is of basic type. If the enumerated type is not specified or the Enumerated annotation is not used, the EnumType value is assumed to be ORDINAL.

如果不使用该注解,就是在上面说的默认的情况是使用Enum中的ordinal属性来完成,所以关于这部分就不详细阐述了。

主要说明一下将Enum类型映射成字符串的方式,其实只是将Enum类型上的注解改为@Enumerated(EnumType.STRING)即可,如下:

@Entity
public class Person implements Serializable{
    private static final long serialVersionUID = 8849870114127659929L;

    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column
    @Enumerated(EnumType.STRING)
    private Gender gender;

    public Person(String name, Gender gender){
        this.name = name;
        this.gender = gender;
    }

    // getter、setter
}

此时看到生成的表结构如下:

这里可以看出Enum类型字段Gender**被映射成VARCHAR(255)类型**,通过往里面插入一条数据看一下结果,如下:

@Test
public void testJpa(){
    personService.save(new Person("Jhon", Gender.male));
    personService.save(new Person("Lily", Gender.female));
}

可以看出是插入的对应Enum类型的name属性,就是这么简单!

3. 使用AttributeConverter属性类型转换器

关于AttributeConverter<X, Y>

  • X 是实体属性的类型
  • Y 是数据库字段的类型
  • Y convertToDatabaseColumn(X) 作用:将实体属性X转化为Y存储到数据库中,即插入和更新操作时执行;
  • X convertToEntityAttribute(Y) 作用:将数据库中的字段Y转化为实体属性X,即查询操作时执行;

使用AttributeConverter可以将Enum中的属性名转换成数据库中存储的字段名,定义一个属性转换器如下:

@Converter
public class GenderConverter implements AttributeConverter<Gender, String> {

    @Override
    public String convertToDatabaseColumn(Gender attribute) {
        return attribute.getValue();
    }

    @Override
    public Gender convertToEntityAttribute(String dbData) {
        return Gender.fromString(dbData);
    }
}

所有的属性转换器需要实现AttributeConverter接口,这个接口可以将实体中的数据转换成到数据库中存储,这种方式可以用来映射实体属性,也可以用来将实体中数据加密存储到数据库中,这个转换器还需要使用@Converter注解标识出来。

下面要重写我们的Gender枚举类,如下:

public enum Gender {
    male("男"),
    female("女");

    private String value;
    private Gender(String value){
        this.value = value;
    }

    public String getValue(){
        return this.value;
    }

    public static Gender fromString(String value){
        Objects.requireNonNull(value, "value can not be null");
        Gender gender = null;
        if("男".equals(value)){
            gender = male;
        }
        else if("女".equals(value)){
            gender = female;
        }
        return gender;
    }
}

下面使用这个转换器如下:

@Entity
public class Person implements Serializable{
    private static final long serialVersionUID = 8849870114127659929L;

    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column
    @Convert(converter = GenderConverter.class)
    private Gender gender;

    public Person(String name, Gender gender){
        this.name = name;
        this.gender = gender;
    }

    // getter、setter
}

生成的数据库结构如下:

可以看出和使用@Enumerated(EnumType.STRING)生成的类型是相同的,但是别急,看看插入的数据是怎么样的?

@Test
public void testJpa(){
    personService.save(new Person("Jhon", Gender.male));
    personService.save(new Person("Lily", Gender.female));
}

结果如下:

可以看出插进去的数据已经不是Enum实例的name属性值了,而是我们自定义的value值。


相关文章:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Hibernate中枚举Enum类型的映射策略 的相关文章

  • centos7下对存有服务的硬盘非LVM分区进行扩容

    文章目录 前言背景 一 环境说明 二 操作步骤 1 暂停服务 备份数据 2 卸载硬盘 3 操作硬盘分区所在的硬盘 4 把新建的硬盘分区做成逻辑卷 1 检查是否安装逻辑券软件包 2 建立物理卷 3 建立卷组 4 建立逻辑卷 5 格式化 并 挂
  • 深入理解C语言中的移位运算

    深入理解C语言中的移位运算 移位运算 C语言还提供了一组移位运算 以便向左或者向右移动位模式 对于一个位表示为 xn 1 xn 2 x0 的操作数x C表达式x lt
  • Centos 7 LVM xfs文件系统修复

    情况1 sda Assuming drive cache write through Internal error xfs XFS WANT CORRUPTED GOTO at line 1662 of file fs xfs libxfs
  • 线程控制

    1 线程相关函数 1 1 CreateThread windows系统函数 beginthread C C 运行库提供的创建线程函数 如果要在多线程中使用C C 运行库 需要使用该函数进行创建线程 该函数内部会初始化某些C运行时变量 并在内
  • oracle查询用户及查看表空间

    查询用户 查看数据库里面所有用户 前提是你是有dba权限的帐号 如sys system select from dba users 查看你能管理的所有用户 select from all users 查看当前用户信息 select from
  • R语言——(三)、随机数与抽样模拟

    文章目录 前序r d p q 一 一元随机数的产生 1 均匀分布随机数runif 2 正态分布随机数的产生rnorm 3 指数分布随机数产生rexp 4 二项分布随机数的产生rbinom 二 多元随机数的产生mv rm pm 1 多元正态分
  • wkhtmltopdf 实现在每一个pdf页面的header或者footer加入html碎片,类似水印的功能

    当我们的项目中需要将html转换成PDF时 并且需要在每一个pdf页面上的header部分加入自己的html碎片 可以使用如下命令 wkhtmltopdf header html http localhost 8080 static dat
  • strlen()与sizeof()辨析

    一 简介 头文件 功能 strlen string h 计算给定字符串的 unsigned int型 长度 不包括 0 在内 sizeof 无 判断数据类型长度符的关键字 二 区别 strlen 是一个函数 它用来计算指定字符串 str 的

随机推荐

  • springboot + vue + poi模板导出

    1 后端代码编写 查找文件所放位置 File file new File ResourceUtils getURL classpath getPath File templateFile new File file static xls m
  • 树图区块链学习(未完待续)

    树图区块链基本结构 1 每个区块只有一条父边指向父区块 2 每个区块可能有多条关联边指向 happen before 关系的区块 确定区块链的主链 1 从创世区块开始 2 迭代深入选择最重的分支作为主链 比如这个区块链中 子树A所在分支即为
  • torch.mean

    mean 函数的参数 dim 0 按行求平均值 返回的形状是 1 列数 dim 1 按列求平均值 返回的形状是 行数 1 默认不设置dim的时候 返回的是所有元素的平均值 x torch arange 12 view 4 3 注意 在这里使
  • 4G LTE各band对应的频率一览表

    4G LTE各band对应的频率一览表 在调试过程中 有时对band具体的频率不清楚 这里记录一下
  • Django实现media、static静态资源通过url加载访问

    Django实现media static静态资源通过url加载访问 Django项目中一般上传的静态文件会存储在根目录的media文件夹下 template模板使用的静态css js image等文件存在static目录下 所以如何配置me
  • melogin.cn主页登录_melogin.cn登录官网

    问 melogin cn官网登录不进去怎么办 答 请注意 melogin cn 是水星路由器的登录地址 并不是一个能在互联网上访问的网站 如果在设置水星路由器的时候 不能进入melogin cn登录官网页面 请仔细阅读下面的解决办法 温馨提
  • 解释执行和编译执行的区别、基于栈和基于寄存器的指令集区别

    1 解释执行和编译执行的区别 我们在学习java的时候 对class文件都有个疑惑 虚拟机是如何执行发方法中的字节码指令的呢 其实 虚拟机的执行引擎在执行java代码的时候有解释执行和编译执行两种选择 通俗说来 解释执行是通过解释器执行 编
  • Altium Designer 20(AD20)新手小白详细教程

    目录 AD20的操作 控制界面操作 将原理图导入PCB中 添加库文件 放置图标 将连线由90 变为45 在英文状态下按shift 空格可以改变线连接的角度 整体修改标号 设置元件镜像对称快捷键 管脚设置 新建元器件 在同一个原理图库内新建多
  • nginx安装http_ssl_module模块,支持https

    1 进入源码包 如 cd usr local nginx 1 15 0 2 运行nginx V命令查看已经安装的nginx模块 configure arguments 后面表示当前已经安装的nginx模块 如 root izbp11gsqd
  • 高等数学(工本)选择题

    线性运算案例 向量运算案例 求曲面方程 求平面方程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 3
  • 最新Python入门基础教程2023

    目录 前言 安装Python 变量和数据类型 运算符 控制流语句 函数 列表 字典 循环 for循环 while循环 条件语句 if语句 if else语句 异常处理 其他基础知识 前言 学习Python的基础知识对于
  • 2022经历裁员之后,我总结了程序员必备的架构能力!

    一 前情回顾 上篇文章 同事老是吐槽我的接口性能差 原来真凶就在这里 聊了一下系统架构中的查询平台 我们采用冷热数据分离 冷数据基于HBase Elasticsearch 纯内存自研的查询引擎 解决了海量历史数据的高性能毫秒级的查询 热数据
  • 华为交换机CE12808导入导出配置文件

    1 创建FTP用户 开启ftp服务 ftp server enable 设置ftp默认文件目录 set default ftp directory flash 进入AAA视图 aaa 设置用户 密码 local user 用户名 passw
  • 代价函数

    一 什么是代价函数 我在网上找了很长时间代价函数的定义 但是准确定义并没有 我理解的代价函数就是用于找到最优解的目的函数 这也是代价函数的作用 二 代价函数作用原理 对于回归问题 我们需要求出代价函数来求解最优解 常用的是平方误差代价函数
  • 普通大专真的可以自学 Java 吗?

    能是肯定能 看数据先 全国范围内搜索Java筛选大专学历 1到 3年工作经验 找到了1177条消息 但是其他条件不变 更改本科呢 全国范围内搜索到了3215条招聘消息 有人说什么90 以上都要本科 确实有点片面了 当然现在也不是招聘旺季 已
  • HashMap的底层实现。(05)

    HASHMAP的简介 通过学习本文档后能够掌握到的知识点 1HashMap的简单介绍 2HashMap的主要方法 3模仿JAVA写一个简单的HASHMAP 子曰 学而不思则罔 思而不学则殆 1 为什么学HASHMAP 作为MAP接口下面一个
  • springboot学习(七)Thymeleaf模板引擎

    模板引擎 springboot我们目前是以jar包的形式打包 实际上我们之前是打成war包 放到tomcat服务器里面 可以用JSP 但是jar包就导致不能用JSP 换一种方式就是springboot推荐的Thymeleaf模板引擎 JSP
  • npm 换淘宝源

    npm config get registry npm config set registry https registry npm taobao org
  • cURL安装和常用实例

    cURL是一个利用URL语法在命令行下工作的文件传输工具 配置后 可以在命令行直接执行各类操作 也可以作为源码包 载入到各类后端开发 为后端提供文件传输能力 安装 下载 演示电脑是win10 64位 下载对应的包 全部下载地址 zip地址
  • Hibernate中枚举Enum类型的映射策略

    在Java中Enum是一种 奇葩 的存在 奇葩 不代表没用 对于这种比较特殊的存在 hibernate会有很多种选择来完成Enum类型字段的映射 首先要说明的是在hibernate都是把Enum类型的字段映射成基本类型的字段 并且我这里不使