@Enumerated的使用

前言

今天做测试,发现还没有试过实体类中关于枚举项的使用,于是就做了个测试,发现了点问题(发现的问题主要是针对我使用的ORM框架是Ebean,它自带了一个比@Enumerated更好用的注解和方式)。

不多说,直接进行说明 。。。


@Enumerated的使用测试

比如我有一张表,有一个字段是性别gender,这个字段我只想设置男女,于是我就想到了枚举,建表如下:

CREATE TABLE `j_test2` (	-- 忽略这里的表名,只是为了测试
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(30) DEFAULT NULL,
  `gender` int(10) DEFAULT NULL, -- 注意这里性别使用了int类型,和@Enumerated会有关系
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

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

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

定义的枚举如下:

package demo.springboot.cons;

/**
 * @author jiangkd
 * @date 2022/12/13 14:35:58
 */
public enum Gender {

    /**
     * 男
     * ordinal是0, name是MALE
     */
    MALE,
    /**
     * 女
     * ordinal是1, name是FEMALE
     */
    FEMAL

}

我们的实体类如下:

package demo.springboot.entity;

import demo.springboot.cons.Gender;
import lombok.*;
import lombok.experimental.Accessors;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;

/**
 * @author j
 * @date 2022/12/13 14:34:45
 */
@Accessors(chain = true)
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Entity
// ORM使用的是Ebean,不是Mybatis,实体类会有所不同
@Table(name = "j_test2")
public class Jtest2 {

    private Integer id;

    private String name;
    /**
    * 性别使用了枚举
    */
    @Column(name = "gender")
    private Gender gender;
}

1.1.不使用注解@Enumerated

其实,不使用注解,默认的就是@Enumerated(EnumType.ORDINAL),也就是实体类gender属性改为如下:

	@Enumerated(EnumType.ORDINAL)
    @Column(name = "gender")
    private Gender gender;

测试插入两条数据:

package demo.springboot.enum_;

import demo.springboot.DemoSpringbootApplication;
import demo.springboot.cons.Gender;
import demo.springboot.entity.Jtest2;
import io.ebean.Database;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @author j
 * @date 2022/12/13 14:42:51
 */
@SpringBootTest(classes = DemoSpringbootApplication.class)
@RunWith(SpringRunner.class)
@Slf4j
public class Jtest2Test {

    @Autowired
    Database database;

    @Test
    public void add() {
        //
        final Jtest2 jtest = new Jtest2()
                .setName("test1")
                // 设置枚举MALE
                .setGender(Gender.MALE);
        // 保存到数据库
        database.save(jtest);

        final Jtest2 jtest2 = new Jtest2()
                .setName("test2")
                // 设置枚举FEMALE
                .setGender(Gender.FEMAL);
        // 保存到数据库
        database.save(jtest2);
    }
}

查看数据库:
@Enumerated的使用_第1张图片
可以看出,插入数据的时候,gender列对应的就是枚举项的ordinal序号,第一个MALE就是0,第二个FEMALE是1。这样就存在一个问题,如果我们又添加了一个OTHER的枚举项,放在了MALE后面,此时他们的ordinal序号就变了(MALE是0,OTHER是1,FEMALE就成了2了),这样的已经存入数据库的gender数据就和枚举项不对应了,容易出现问题。

所以我们推荐使用下面的方式,不存储枚举项的ordinal了,而是它的name。

1.2.使用@Enumerated(EnumType.STRING)

我们的枚举不动,依然是只有MALE和FEMALE,只是修改实体类中gender属性,添加注解@Enumerated(EnumType.STRING),如下:

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

注意,一开始我们创建j_test2表的时候,gender属性我们使用的int类型,就是为了第一种方式存储枚举项的ordinal序号,而现在我们要存在的是枚举项的name(MALE,FEMALE),所所以数据库的gender类型要改为varchar类型,如下:

alter table j_test2 modify column gender varchar(10) null comment '性别';
truncate table j_test2; -- 清空数据, 便于测试查看

我们再次执行上面Jtest2Test的add方法 。。。

再次查看数据库:
@Enumerated的使用_第2张图片
咋样,此时gender存储的是枚举项的name了,这样就算枚举项添加,删除(ordinal变化)也没事了,因为我们存储的是name。

总结

虽然以上的使用没有什么问题,但有没有觉得怪怪的。

首先使用@Enumerated(EnumType.ORDINAL)的方式,就存在修改枚举项导致ordinal变化的问题。

其次使用@Enumerated(EnumType.STRING)的方式,也并没有达到我想要的效果,它只是存储了name,我想要的是数据库存储枚举项的构造参数值,查询或保存的时候使用的枚举项的name。(肯定有方式,但是我不想特殊处理一下之类的,就是直接使用即可那种)

我用的ORM框架式Ebean,发现Ebean中有个注解是@DbEnumValue,确实是我需要的。

你可能感兴趣的:(ORM,#,Ebean,#,springboot,java,spring,boot)