地址作为休眠中的实体或值类型
Address as Entity or Value type in hibernate
我对 Hibernate 中的 entity vs value type
有疑问。
我们以User
和Address
为例。在这里,User 是一个 entity
,我们将 Address 设为 component
。
如果一个用户只能有一个地址,那么在这种情况下,只有一个 table 用户,地址没有 table,因为它被映射为组件。但是,假设一个用户可能有多个地址,那么在这种情况下,除了用户之外,我们还需要另一个 table,用于该映射。
在这里,我有两个选项 first
,Address as entity 和 second
Address as component。
我知道地址没有 shared reference
所以它不需要映射为实体和映射地址作为组件。但是,在这种情况下,我可以将地址映射为实体(没有人阻止我这样做)。所以,我的问题是,如果我将 Address 映射为实体而不是组件,它会有任何缺点吗?
Java
本身没有组成的概念。
A class
或 attribute
无法标记为组件或组合。唯一的区别是对象标识符。
组件没有身份,因此持久化组件class不需要标识符属性或标识符映射。
Hibernate
将术语组件用于用户定义的 class
,它与拥有实体保持在相同的 table,但在一对一的情况下并非如此一个映射。它们之间的差异非常小:一个有一个 id,另一个没有并且存在于原始 class
中。
地址实体有以下缺点:
- 数据库中的性能,因为您需要额外的:
- 加入 select + 外键约束
- 额外的主键生成器+地址的主键索引(它也会增加数据库大小)
- Hibernate 中的性能和内存:每个实体在 Hibernate 中都有很多运行时支持。例如。 hibernate 实体缓存级别 1 - 默认情况下启用(事务级别缓存)。一个实体有 20 个字段比 2 个实体每个有 10 个字段 + 它们之间的关系更便宜。
如果一个用户只能有一个地址,那么这个决定就变成了性能、安全和风格偏好的问题。
正如其他人所指出的,如果将地址映射为@Embedded 而不是单独的@Entity,性能会稍好一些。但是,无法更好地回答问题 "how much" 性能是否取决于您的用例和数据。影响性能的因素包括网络延迟、数据库碎片(真空状态)、数据库索引的创建以及休眠配置(延迟加载与急切加载)。关于 "which is better" - 在考虑所有这些因素之前,无法真正回答这个问题。我可以告诉你,我有一个拥有 N 百万用户的数据库,平均每个用户有 15 个地址。我 运行 一个 select 并在 120 毫秒内检索到用户,另一个 select 在 109 毫秒内检索该用户的所有地址。但是,这并不能帮助您回答您的问题,因为您的数据分布不同,您会遇到不同的网络延迟、不同的数据库响应时间。
选择映射作为@Embedded 的原因:
- 高性能对于您的用例或应用程序至关重要。 N 毫秒对您的应用程序真的很重要吗?
- DB 使用的磁盘存储较少。
- 您不是从头开始创建数据库。你有一个预先存在的数据库模式,你想通过 Hibernate 访问它但不能修改模式
- 您将始终(或几乎总是)在加载用户时访问地址对象。
- 您确信运行永远不需要为单个用户存储多个地址,或者您知道不需要以关系方式根据地址查询用户。这将允许您将地址集合序列化为数据库中的 clob 或 blob。根据您的操作方式,个人地址数据仍然可以访问和查询,但会变得更有趣。
选择映射作为单独的@Entity 的原因
- 风格偏好以及额外的延迟和开销是可以接受的。
- 希望在未来支持单个用户拥有多个地址的可能性,并且希望通过地址数据filter/query。
- 对于地址不相关的用例,您通常需要用户。
- 一个相关的项目:网络带宽是一个问题,您希望 运行在网络上传输尽可能少的数据作为绝对必要的并且地址数据只会在加载用户时不经常访问(配置为惰性-load)
- 您想对两个数据集拥有不同的 DB g运行t 权限。即允许一个用户(在这种情况下,可能是不同的应用程序)更新用户名但不能更新地址,而允许另一个用户同时更新两者。
- 有些用户没有地址,您希望避免空值检查。空集合是您的风格偏好。
我对 Hibernate 中的 entity vs value type
有疑问。
我们以User
和Address
为例。在这里,User 是一个 entity
,我们将 Address 设为 component
。
如果一个用户只能有一个地址,那么在这种情况下,只有一个 table 用户,地址没有 table,因为它被映射为组件。但是,假设一个用户可能有多个地址,那么在这种情况下,除了用户之外,我们还需要另一个 table,用于该映射。
在这里,我有两个选项 first
,Address as entity 和 second
Address as component。
我知道地址没有 shared reference
所以它不需要映射为实体和映射地址作为组件。但是,在这种情况下,我可以将地址映射为实体(没有人阻止我这样做)。所以,我的问题是,如果我将 Address 映射为实体而不是组件,它会有任何缺点吗?
Java
本身没有组成的概念。
A class
或 attribute
无法标记为组件或组合。唯一的区别是对象标识符。
组件没有身份,因此持久化组件class不需要标识符属性或标识符映射。
Hibernate
将术语组件用于用户定义的 class
,它与拥有实体保持在相同的 table,但在一对一的情况下并非如此一个映射。它们之间的差异非常小:一个有一个 id,另一个没有并且存在于原始 class
中。
地址实体有以下缺点:
- 数据库中的性能,因为您需要额外的:
- 加入 select + 外键约束
- 额外的主键生成器+地址的主键索引(它也会增加数据库大小)
- Hibernate 中的性能和内存:每个实体在 Hibernate 中都有很多运行时支持。例如。 hibernate 实体缓存级别 1 - 默认情况下启用(事务级别缓存)。一个实体有 20 个字段比 2 个实体每个有 10 个字段 + 它们之间的关系更便宜。
如果一个用户只能有一个地址,那么这个决定就变成了性能、安全和风格偏好的问题。
正如其他人所指出的,如果将地址映射为@Embedded 而不是单独的@Entity,性能会稍好一些。但是,无法更好地回答问题 "how much" 性能是否取决于您的用例和数据。影响性能的因素包括网络延迟、数据库碎片(真空状态)、数据库索引的创建以及休眠配置(延迟加载与急切加载)。关于 "which is better" - 在考虑所有这些因素之前,无法真正回答这个问题。我可以告诉你,我有一个拥有 N 百万用户的数据库,平均每个用户有 15 个地址。我 运行 一个 select 并在 120 毫秒内检索到用户,另一个 select 在 109 毫秒内检索该用户的所有地址。但是,这并不能帮助您回答您的问题,因为您的数据分布不同,您会遇到不同的网络延迟、不同的数据库响应时间。
选择映射作为@Embedded 的原因:
- 高性能对于您的用例或应用程序至关重要。 N 毫秒对您的应用程序真的很重要吗?
- DB 使用的磁盘存储较少。
- 您不是从头开始创建数据库。你有一个预先存在的数据库模式,你想通过 Hibernate 访问它但不能修改模式
- 您将始终(或几乎总是)在加载用户时访问地址对象。
- 您确信运行永远不需要为单个用户存储多个地址,或者您知道不需要以关系方式根据地址查询用户。这将允许您将地址集合序列化为数据库中的 clob 或 blob。根据您的操作方式,个人地址数据仍然可以访问和查询,但会变得更有趣。
选择映射作为单独的@Entity 的原因
- 风格偏好以及额外的延迟和开销是可以接受的。
- 希望在未来支持单个用户拥有多个地址的可能性,并且希望通过地址数据filter/query。
- 对于地址不相关的用例,您通常需要用户。
- 一个相关的项目:网络带宽是一个问题,您希望 运行在网络上传输尽可能少的数据作为绝对必要的并且地址数据只会在加载用户时不经常访问(配置为惰性-load)
- 您想对两个数据集拥有不同的 DB g运行t 权限。即允许一个用户(在这种情况下,可能是不同的应用程序)更新用户名但不能更新地址,而允许另一个用户同时更新两者。
- 有些用户没有地址,您希望避免空值检查。空集合是您的风格偏好。