@Enumerated的使用

本文探讨了使用不同注解在数据库中存储枚举类型的方法,包括@Enumerated(EnumType.ORDINAL)和@Enumerated(EnumType.STRING),并指出各自的优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

今天做测试,发现还没有试过实体类中关于枚举项的使用,于是就做了个测试,发现了点问题(发现的问题主要是针对我使用的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);
    }
}

查看数据库:
在这里插入图片描述
可以看出,插入数据的时候,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方法 。。。

再次查看数据库:
在这里插入图片描述
咋样,此时gender存储的是枚举项的name了,这样就算枚举项添加,删除(ordinal变化)也没事了,因为我们存储的是name。

总结

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

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

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

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

要查询`Equipment`表中所有`equipmentType`等于`TypeA`的记录,您可以使用Spring Data JPA的命名规则自定义查询方法。请按照以下步骤进行操作: 首先,在`Equipment`实体类中添加一个自定义查询方法,使用Spring Data JPA的命名规则来定义查询逻辑: ```java @Repository public interface EquipmentRepository extends JpaRepository<Equipment, Long> { List<Equipment> findByEquipmentType(EquipmentType equipmentType); } ``` 在上述代码中,`findByEquipmentType()`方法使用Spring Data JPA的命名规则来定义查询逻辑。根据命名规则,Spring Data JPA会自动生成查询语句,查询`Equipment`表中所有`equipmentType`等于指定值的记录。 然后,在您的服务类(例如,`EquipmentService`)中注入`EquipmentRepository`,并调用该方法来获取满足条件的记录: ```java @Service public class EquipmentService { private final EquipmentRepository equipmentRepository; public EquipmentService(EquipmentRepository equipmentRepository) { this.equipmentRepository = equipmentRepository; } public List<Equipment> findEquipmentsOfTypeA() { return equipmentRepository.findByEquipmentType(EquipmentType.TypeA); } } ``` 在上述代码中,`findEquipmentsOfTypeA()`方法调用了`findByEquipmentType()`方法,并传入`EquipmentType.TypeA`作为参数,以获取所有满足条件的记录。 通过这种方式,您可以使用Spring Data JPA和基于命名规则的查询方法来查询`Equipment`表中所有`equipmentType`等于`TypeA`的记录。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值