例如,当您为除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;
在我的user pojo类中:如果我没有为user_id
定义id注解,而是为user_email
定义id注解,那么从长远来看,这会产生任何复杂的情况吗?
发布于 2018-09-04 06:12:21
这是一种糟糕的做法。
电子邮件可能会改变,但主键(这是@Id
注释的内容)永远不应该改变。用户名也可能会改变,比如在这个网站上。
发布于 2018-09-04 07:28:45
首先让我说:这是一个很好的问题!对此的简短回答是:
No,使用
@Id
注释user_email
或username
等字段不是一种好的做法。
为了更深入地了解为什么,让我们首先记住主键(PK)是如何定义的。在大多数面向SQL的数据库系统中,PK definition至少遵循两个假设,在这两个假设下,PK始终为:
与您的想法/问题相关的含义:
在可以将User
实例持久化到数据库之前,应该已经将username
或user_email
值设置为该实例。在这种情况下,它丢失了,或者只有在稍后的时间点才能知道:持久性=不可能。反之亦然,它永远不会被设置为未知值,也就是null
,例如,如果用户根本不能提供他/她的电子邮件地址(即使2018年很少)。
在大多数应用程序中,username
/user_email
的实际值往往是唯一的。然而,在应用程序的业务逻辑中,您必须确保其他用户不会两次输入已经存在/已知的username
/user_email
。如果您对持久性进行了注释,那么再次声明:@Id
= If。不过,最有可能的情况是,允许这些字段中的一个字段存在重复项将以任何方式违反其语义。
如果您将user_id
注释为@Id
字段:在两种情况下都没有问题。
在ORM上下文中,the JPA specification document扩展了这个定义,并在第31页说明:
其主键的值唯一地标识持久化上下文中的实体实例和EntityManager操作,如第3章“实体操作”中所述。应用程序不得更改主键的值。如果发生这种情况,行为是未定义的。
这就产生了下一个含义
根据定义,您不允许以编程方式/在运行时更改@Id
字段的值。这些字段的控制应该保持在实现JPA specification.的对象关系映射器的一侧
正如在回答中指出的那样,username
或user_email
可能会在应用程序的生命周期中发生变化。原因:从应用程序用户的角度来看,数据是不稳定的。用户可能想要更改这些属性(在未来的某个时间),例如,如果他们结婚或更改他们的电子邮件提供商。
但是,通常可以注释类型为String
(和其他类型)的字段,请参见第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
;这样,在您作为软件开发人员的有生之年(对于99.5%以上的应用程序是正确的),您将拥有足够的主键值。
https://stackoverflow.com/questions/52026469
复制相似问题