java emun ordinal_关于Java:JPA枚举ORDINAL与STRING

可以使用以下任一方法在JPA中定义枚举

@Enumerated(EnumType.ORDINAL)

要么

@Enumerated(EnumType.STRING)

我想知道这两个定义的优缺点是什么?

我听说ORDINAL的性能比EclipseLink的STRING更好(更快)。

真的吗?

我认为ORDINAL默认情况下不使用@Enumerated批注

在JPA 2.1中,您可以指定@Converter并允许映射到字符串或其他数据类型,该类型可以是简单/简短,也可以是长/复杂。

我总是去STRING。

速度很少是最重要的问题-可读性和可维护性更为重要。

我使用STRING是因为从数据库中手动检查行要容易得多,但是更重要的是,我可以做两件事,而无需接触数据库,ORDINAL无法处理:

我可以更改枚举的顺序

我可以在枚举列表的中间插入新的枚举

这两个更改都将更改数据库中已在使用的枚举的序数值,从而在使用ORDINAL时破坏现有数据。

如果更改枚举值(不是很常见),则处理起来很简单:

UPDATE table SET enum_column = 'NEW_ENUM_NAME' where enum_column = 'OLD_ENUM_NAME';

另一方面,您不能重命名枚举。 ;)我不会说有一个首选的。

确保可以:`UPDATE table SET enum_column = NEW_ENUM其中enum_column = OLD_ENUM

重命名Enums就像重命名表或表中的列一样会带来灾难性的后果,它已经产生了长远的不平凡的影响,我不认为这是个问题,因为这样的大变化将被仔细考虑。您更有可能添加新的枚举而不删除或重命名它们,而不必担心更改序数位置对于外部代码更为重要,因为外部代码在编译时无法检查,重命名可以。最后,客户端代码不必关心您使用哪个代码,名称更易于维护。

如果有人不知道该数据库中使用了枚举名称,则不会。我会说我重命名枚举的次数要比重新排序的次数多。而且您也可以使用常规的UPDATE查询

"灾难性"这个词太令人动容,无法描述重命名枚举-有关简单处理,请参见答案。

如何在数据库和代码中同时更新enum名称?

@Sangdol将是一个释放任务:重命名枚举后,在释放代码时,运行sql脚本以更新所使用的枚举名称:update mytable set myenumcol = newname where myenumcol = oldname

Ordinal的优点是始终使用@OrderBy,而使用String时,排序是按字母顺序进行的(这里我是说db SELECT语句)。

@ 1in9ui5t有趣的一点是,尽管大多数数据库都有按枚举排序的方式。特别是,如果您也将该列也实现为mysql枚举,则按枚举顺序排序,如果可以使用纯字符串,则可以order by find_in_set(mycolumn, ENUM_NAME_1, ENUM_NAME_2, ...)(有点难看,但足够简单)

@Bohemian我不知道数据库中的ENUM类型。这样就解决了订购问题。只需在列定义中包括Enum值即可。

ORDINAL可能更有效,但这是次要的。 ORDINAL有一些缺点:

它在数据库中不太可读

如果您对枚举定义重新排序,则数据库将不一致。

使用STRING,您无法重命名枚举。

选择其中之一并在整个应用程序中使用它-保持一致。

如果您的数据库将被其他客户端/语言使用-使用STRING,它更具可读性。

我更喜欢使用ORDINAL,但这确实取决于使用情况。

例如:

您有一个枚举,可以保存所有用户状态,在这种情况下,顺序无关紧要,并且将来可以添加更多状态(最佳用法是@Enumerated(EnumType.ORDINAL)):

public enum UserStates { ACTIVE, DELETED, PENDING }

但是现在,您有了一个枚举,将植物保存在太阳系中(最佳使用@Enumerated(EnumType.STRING)):

public enum Planets {MERCURY,VENUS,EARTH,MARS,JUPITER,SATURN,URANUS,NEPTUNE,PLUTO,NINE}

现在,您想使用@Enumerated(EnumType.ORDINAL)来重新排序行星,因为数据库无法知道Java文件中的新次序。

您可以使用@Enumerated(EnumType.STRING)重新排序Plantes,因为您的Planet链接到枚举名称,而不是枚举顺序。

无论如何,您可以修改@Enumerated(EnumType.STRING)枚举,因为它们已链接到订单,但是您无法更改@Enumerated(EnumType.STRING)枚举,因为它们将像新枚举一样使用。

字符串类型在数据库中更具可读性,但比序数数据占用更多的大小。如果数据库被更多的客户端使用,可能会很有用,但是最好是拥有一个良好的软件文档,而不是将" EARTH"保存为" 4"比保存1000倍。

USERSTATE

------------

ID | STATE |

------------

1 | 1

2 | 2

3 | 1

Planets

------------

ID | Name |

------------

1 | EARTH

2 | EARTH

3 | MARS

4 | EARTH

这是一个很好的问题。过去我使用String,但今天我的偏好通常是Ordinal。

字符串的主要缺点是对于DBA。使用String时,他们不知道列的可能值是多少,因为此信息在应用程序代码中。 DBA只能对将表上的现有信息分组的可能值有所了解,但是他永远不会确定其他可能的值或是否添加了新值,直到应用程序将它们插入表中为止。

在Ordinal中,您有同样的问题。但是我更喜欢Ordinal来解决数据库似乎很自然的DBA问题。您创建一个新表以在数据库上显示枚举数的可能值,并在列(常规枚举值)和此新表之间使用外键。在此描述和实施此策略。

关于有人可以对Enumerator进行重新排序并破坏系统的问题,一个简单的单元测试可以解决此问题,并确保没有人在没有良好警告的情况下对其进行重新排序。在重命名枚举器时,同样的想法是有效的。因此,意外地重命名(在String上)或重新排序(在Ordinal上)并不是针对String或Ordinal方法的强烈反对。

顺便说一句,开发人员比重命名Enumerator更需要重命名,因此这是使用Ordinal的另一个积极方面。

因此,使用这种方法,您可以解决Ordinal的主要问题(现在已经可以读取)了,该信息将在数据库上占用更少的空间,并且DBA会很高兴。

我更喜欢EnumType.STRING。

EnumType.ORDINAL的一个缺点是时间的影响以及保持枚举逻辑顺序的愿望。使用EnumType.ORDINAL必须将任何新的枚举元素添加到列表的末尾,否则您将不小心更改所有记录的含义。

请检查此链接:

https://tomee.apache.org/examples-trunk/jpa-enumerated/

这里有很多好的建议,但是我只想添加一些我尚未看到的东西:

无论您选择哪种解决方案,都不要忘记在枚举类的顶部添加一个大的警告提示,指出应该使用哪种警告。希望其他开发人员可以看到您已经完成此操作,并使用相同的方法来保存枚举。

这取决于您的应用程序,是否有更多的机会使用String类型添加更多的枚举,是否有更多的机会使用Ordinal更改枚举的名称。

您真的确定需要人类可读的数据库吗?

存储字符串值是浪费空间。可读性的唯一折衷办法是使用@Enumerated(STRING)并将map数据库列作为ENUM使用(如果您使用的是mysql ...我想其他dbms也有类似的用法),但是当您必须更改枚举名称时,这确实很痛苦。

(讽刺评论警告)是的,这样更好,因为必须仔细检查代码才能找到该序数值的实际含义。...哦,别忘了排序-当有人在枚举的中间/顶部插入一个新值时,效果很好。不要让实现决定设计。 @Enumerated(ORDINAL)被认为是有害的

可维护性和可读性比您所说的重要得多。这些东西(空间)在服务速度和内存消耗方面几乎完全没有成本。当您最终由于此类问题而解决问题时,这会立即使您付出代价(比空间大)。

@earcam(讽刺的回答),您随时可以在列上添加评论,并在需要时随时阅读。这难读吗?恕我直言,这张票没有回答这个问题,两种情况各有利弊

@dwilda哈哈,很公平。但是可以肯定的是,基数+(复合)索引可以缓解任何性能问题...不匹配已经很严重了?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值