首页 > 解决方案 > mysql:为什么我需要 AttributeConverter over enum 将具有枚举数据类型的 DB 列映射为枚举与 JPA 实体?

问题描述

我有一个user数据库表:

CREATE TABLE IF NOT EXISTS `user` (
  `user_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `first_ name` VARCHAR(45) NOT NULL,
  `active_status` ENUM('ACTIVE', 'PENDING', 'DEACTIVATED', 'BLOCKED', 'SPAM', 'DELETED') NOT NULL ,
  UNIQUE INDEX `unique_id_UNIQUE` (`unique_id` ASC),
  UNIQUE INDEX `email_UNIQUE` (`email` ASC),
  PRIMARY KEY (`user_id`))
ENGINE = InnoDB;    

我将它映射到相应的 JPA 实体类:

@Entity
public class User implements OfloyEntity {

@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "user_id", unique = true, nullable = false)
private int userId;

//other fields

@Enumerated(EnumType.STRING)
@Column(name = "active_status", nullable = false, length = 11)
private UserStatus activeStatus;

如您所见,我已映射activeStatus到 aenum UserStatus以限制持久层本身的整体。

public enum UserStatus {

    ACTIVE,
    PENDING,
    DEACTIVATED,
    BLOCKED,
    DELETED,
    SPAM
}

我想知道使用这种方法在持久层中实现数据库枚举有什么缺点吗?我抛出了多篇推荐使用AttributeConverter的文章,但由于我的枚举中的值非常有限并且修改的机会较少,我无法将所有这些文章与我的要求联系起来。

有什么我遗漏的,或者我的设计可以做任何改进吗?

我扔的文章:
vladmihalcea
thorban和其他一些 stackoverflow 问题。

更新:阅读 Jens 的答案后,我决定实施AttributeConverter(针对用户的gender)。这让我有点困惑:
为什么我决定使用枚举作为 MYSQL 列类型:因为它限制了值并且需要更少的空间。因为 MYSQL 在幕后存储了它的枚举的序数值,并且当被要求输入它代表该字符串值的值时,它节省了空间。
我对性别的实现:

public enum UserGender {

    MALE('M'),
    FEMALE('F'),
    OTHER('O');

    private Character shortName;

    private UserGender(Character shortName) {
        this.shortName = shortName;
    }

    public Character getShortName() {
        return shortName;
    }

    public static UserGender fromShortName(Character shortName) {
        switch (shortName) {
        case 'M': return UserGender.MALE;

        case 'F' : return UserGender.FEMALE;

        case 'O' : return UserGender.OTHER;

        default:
            throw new UserGenderNotSupportedException("user gender with shortName : " + shortName + " not supported");
        }

    }

}

转换器类:

@Converter(autoApply = true)
public class UserGenderConverter implements AttributeConverter<UserGender, Character> {

    @Override
    public Character convertToDatabaseColumn(UserGender userGender) {
        return userGender.getShortName();
    }

    @Override
    public UserGender convertToEntityAttribute(Character dbGender) {
        return UserGender.fromShortName(dbGender);
    }

}

现在,主要的疑问
1. 根据博客,MYSQL enum在 DB 中使用是邪恶的,因为有一天如果我需要向枚举列添加额外的值并且需要一个表 ALTER,但使用的情况不一样AttributeConverter吗?因为我们也使用 a java enum,如果有一天需要新的性别,这需要改变吗?
2. 如果我使用AttributeConverter,我必须在某处记录 java enumUserGender此处)解释,以便 DBA 能够理解 F、M、O 代表什么。我在这里吗?

标签: mysqlhibernatejpaspring-data-jpa

解决方案


这些文章为您提供了丰富的潜在缺点选择:

使用@Enumerated(EnumType.STRING)有以下几点:

  • 与其他选项相比,它使用了大量空间。请注意,这意味着需要通过网络加载和传输更多数据,这也会影响性能。我们不知道这是否对您来说是个问题,并且您也不会知道,直到您进行了一些性能测试。
  • 将枚举值的名称与列值紧密联系起来。这可能是有风险的,因为开发人员习惯于快速重命名东西,并且您需要使用实际的遗留数据进行测试才能捕捉到这一点。

如果您不使用真正大量的数据,而更新所有行的列是一个实际问题,我不会出汗。AttributeConverter当简单的解决方案实际上成为问题时,引入和更新数据很容易。

关于更新问题的更新:

  1. 我不接受任何东西都是“邪恶”的论点,因为它可能需要一个ALTER TABLE声明。根据这个论点,我们应该完全废除关系数据库,因为使用它们需要 DDL,而应用程序的发展将需要更多的 DDL。当然,DDL 语句的必要性使部署更加复杂。但是无论如何,您都需要能够处理这件事。

    但确实,AttributeConverter在这种情况下,您不需要任何 DDL,因为您只需将另一个值放在同一列中,除了值的最大长度之外没有任何特殊约束。这假设您对列没有检查约束来限制合法值。

    1. 您是否必须记录数据库中存储的值之间的关系Enum?取决于你的团队。DBA 是否关心数据的含义?DBA 是否具有理解 Java 代码的访问权限和技能?如果 DBA 需要或想知道并且不能或不会从源代码中获取信息,则必须将其记录在案。真的。

推荐阅读