在用户名或用户电子邮件等属性下使用@Id注释是否是一种好习惯

时间:2018-08-26 12:57:04

标签: java hibernate jdbc

例如,为id以外的文件设置@Id属性时可能会发生什么复杂情况

@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="user_id")
private Integer user_id;

@Id
@Size(min=6,message="email is too short")
@Pattern(regexp = "^.+@.+\\..+$",message="invalid email")
@Column(name="user_email")
private String user_email;

在我的用户pojo类中:如果我不是为user_id定义id注释,而是为user_email定义id注释,从长远来看会不会带来任何麻烦?

2 个答案:

答案 0 :(得分:0)

这是不好的做法。

电子邮件可能会更改,但是主键(@Id所注释的内容)永远不会更改。用户名也可能会更改,例如在此站点上。

答案 1 :(得分:0)

首先让我说:这是一个好问题!简短的答案是:

  

,用user_email注释username@Id之类的字段不是一个好习惯。

要深入了解为什么,让我们首先记住如何定义主键(PK)。在大多数面向SQL的数据库系统中,PK definition至少遵循两个假设,PK始终为:

  • (i)不为空
  • (ii)唯一

与您的想法/问题有关的含义:

  • (a):

    在将usernameuser_email值持久保存到数据库之前,必须将其设置为User实例。在这种情况下,它不存在或仅在以后的某个时间才知道:持久性=不可能。反之亦然,例如,如果用户根本无法提供他/她的电子邮件地址(即使在2018年很少见),则永远不能将其设置为 unknown 值,也称为null

  • (b):

    username / user_email的实际值在大多数应用程序中往往是唯一的。但是,您必须确保在应用程序的业务逻辑中,没有其他用户两次输入已经存在/已知的username / user_email。再次给您添加@Id注释:持久性=不可能。不过,很可能在这些字段之一中允许重复项将以任何方式违反其语义。

如果您将user_id注释为@Id字段:两种情况都没有痛苦。

在ORM上下文中,the JPA specification document扩展此定义并在第31页上指出:

  

其主键的值唯一标识持久性上下文中的实体实例,并   如第3章“实体操作”中所述的EntityManager操作。应用程序不得更改主键的值。如果发生这种情况,则该行为是不确定的。

这产生了下一个含义

  • (c)

    根据定义,您不允许以编程方式/在运行时更改字段的@Id值。此类字段的控制应完全保留在实现JPA规范的对象关系映射器的一侧。

正如 Bohemian 的回答所指出的,usernameuser_email可能会在应用程序的生命周期内发生变化。原因:从应用程序用户的角度来看,数据是不稳定的。用户可能想更改这些属性(在将来的某个时间),例如,如果他们结婚或更改电子邮件提供商。

尽管如此,通常可以注释类型String(及其他)的字段,请参见p。 31:

  

简单主键或复合主键的字段或属性应为以下类型之一:任何Java primitive type;任何原始包装器类型; java.lang.String;   java.util.Date; java.sql.Date; java.math.BigDecimal; java.math.BigInteger

所以有人可能会说:好吧,让我们开始吧!但是,应该退后一步,并反映出(a)应用程序的域或(b)应用程序的预期用例施加在预期应用程序的数据库架构上的内容。如上所述,这在您的情况下尤其重要。

考虑到这些“现实世界”的考虑,最好只给@Id注释一个代理密钥,例如您的示例中的user_id。在数据库的整个生命周期中,这一点都不会改变。问题:为什么不更改?答:没有实际理由满足应用程序用户定义的业务案例。

希望这会有所帮助。

°提示

最好从一开始就使用Long而不是Integer;因此,您将拥有足够的主键值,远远超过了作为SW开发人员的寿命(对于所有应用程序来说> 99.5%都是正确的)。