mysql:为什么我需要在enum上使用AttributeConverter才能将具有enum数据类型的数据库列映射为带有JPA实体的enum?

时间:2018-06-27 14:40:36

标签: mysql hibernate jpa spring-data-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映射到enum UserStatus以限制持久层本身的整体。

public enum UserStatus {

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

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

我是否缺少某些东西,或者可以对我的设计进行任何改进?

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

更新:阅读了Jens的回答后,我决定实施AttributeConverter(针对用户gender)。那让我有些困惑:
为什么我决定将枚举用作MYSQL列类型:因为它限制了值并需要较少的空间。由于MYSQL将枚举的序数值存储在幕后,并且当要求该值表示字符串的String值时,可以节省空间。
我对性别的实现:

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是邪恶的,因为总有一天,如果我需要向enum列中添加额外的值,这将需要一个表ALTER,但使用{{ 1}}?因为我们还使用了AttributeConverter,如果有一天需要新的性别,是否需要更改?
2.如果使用java enum,则必须在某处记录Java AttributeConverter(此处为enum)的解释,以便DBA能够理解F,M,O的含义。我在这里吗?

1 个答案:

答案 0 :(得分:2)

文章为您提供了许多潜在的弊端:

使用@Enumerated(EnumType.STRING)具有以下功能:

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

如果您不能处理大量数据(对于这些数据而言,更新所有行的列是一个实际问题),那么我不会费力。当简单的解决方案实际上成为问题时,引入AttributeConverter并更新数据就很容易了。

有关已更新问题的更新:

  1. 我不认为任何东西都是“邪恶的”,因为它可能需要ALTER TABLE语句。通过这种说法,我们应该完全废除关系数据库,因为使用关系数据库需要DDL,而应用程序的演进将需要更多的关系数据库。当然,DDL语句的必要性使部署更加复杂。但是无论如何,您都需要能够处理此问题。

    但是的确,在这种情况下,使用AttributeConverter不需要任何DDL,因为您只需要在同一列中放入另一个值即可,除了最大长度,该值没有任何特殊约束价值。假设您在该列上没有检查约束来限制合法值。

    1. 是否需要记录Enum与数据库中存储的值之间的关系?取决于您的团队。 DBA甚至关心数据的含义吗? DBA是否具有访问权限和掌握Java代码的技能?如果DBA需要或想要知道并且无法或不会从源代码中获取信息,则必须对其进行记录。是的。