Hibernate 中 DTO 和延迟加载之间有什么关系
What is the relationship between DTO and lazy-loading in Hibernate
我知道什么是DTO:一种在进程之间携带数据以减少方法调用次数的对象。
我知道什么是休眠中的延迟加载。
我在 "Full Stack Development with JHipster" 书中读到以下句子:
JHipster 在服务器端使用 DTO(数据传输对象)和 VM(视图模型)。 DTO 用于在服务层和资源层之间传输数据。它们打破了 Hibernate 事务并避免了进一步延迟加载被资源层触发。
不明白DTO和懒加载的关系
如果您将 Hibernate 管理的持久实体传递给启用了延迟加载的资源层,资源层将调用 get
方法来读取它们的属性,其中一些属性当时可能尚未初始化。然后,Hibernate 将从 persisntet 存储延迟加载特定 属性 的数据,发送一个 SQL 语句(可能每次开始并提交一个新事务)并等待相当慢的响应。如果这种情况发生数百次,每次都必须初始化另一个 属性,每次触发延迟加载,用户都必须等待...
如果您在服务层准备一个 DTO,其中包含与资源层相关的所有数据,则对该 DTO 的读取访问非常高效,而且没有为任何 get
方法调用访问数据库的风险因为所有相关的东西都已经在记忆中了。不会触发后续延迟加载。
简单来说:如果您调用延迟加载标记字段的 getter,Hibernate 将对该数据进行数据库查询。
这是您不应该 return 实体作为后端响应的原因之一...任何 JSON 转换(序列化)/getter 调用都会触发不需要的数据加载.
而 DTO 专门用于根据用途传输数据,您从这些实体创建 DTO(可以从一个实体创建多个 DTO)并仅选择所需的数据字段
例如
用户实体:有用户详细信息和好友列表
UserDetailsDTO:只需要详细信息,不需要将 1000 个朋友映射到用户......和他们的朋友......
UserFriendsDTO:我们可以有选择地获取此 DTO 的好友名称或 ID
延迟加载适用于实体,而非 DTO。
JPA 实体可以表示为 POJO 或 Proxy。
使用 EntityManager.find
给你一个 POJO:
Post post = entityManager.find(Post.class, postId);
虽然 EtityManager.getReference
方法为您提供代理:
Post post = entityManager.getReference(Post.class, postId);
POJO 已初始化其基本属性,因为执行了 SELECT 语句以获取实体。代理在创建时不会访问数据库。只有 id 是根据提供的实体标识符设置的。只有您访问代理属性,才会执行 SELECT 语句。
代理也用于默认使用 FetchType.LAZY
策略的集合(例如 @OneToMany
或 @ManyToMany
)。访问 LAZY 集合后,将执行 SELECT 语句以获取关联的集合。
现在,DTO 基于投影,因此在填充 DTO 之前执行 SELECT 语句。为此,可以说每次都是急切加载DTO。
DTO 比只读投影的实体更有效,因为您只加载您明确请求的 table 列。
我知道什么是DTO:一种在进程之间携带数据以减少方法调用次数的对象。 我知道什么是休眠中的延迟加载。
我在 "Full Stack Development with JHipster" 书中读到以下句子: JHipster 在服务器端使用 DTO(数据传输对象)和 VM(视图模型)。 DTO 用于在服务层和资源层之间传输数据。它们打破了 Hibernate 事务并避免了进一步延迟加载被资源层触发。
不明白DTO和懒加载的关系
如果您将 Hibernate 管理的持久实体传递给启用了延迟加载的资源层,资源层将调用 get
方法来读取它们的属性,其中一些属性当时可能尚未初始化。然后,Hibernate 将从 persisntet 存储延迟加载特定 属性 的数据,发送一个 SQL 语句(可能每次开始并提交一个新事务)并等待相当慢的响应。如果这种情况发生数百次,每次都必须初始化另一个 属性,每次触发延迟加载,用户都必须等待...
如果您在服务层准备一个 DTO,其中包含与资源层相关的所有数据,则对该 DTO 的读取访问非常高效,而且没有为任何 get
方法调用访问数据库的风险因为所有相关的东西都已经在记忆中了。不会触发后续延迟加载。
简单来说:如果您调用延迟加载标记字段的 getter,Hibernate 将对该数据进行数据库查询。
这是您不应该 return 实体作为后端响应的原因之一...任何 JSON 转换(序列化)/getter 调用都会触发不需要的数据加载.
而 DTO 专门用于根据用途传输数据,您从这些实体创建 DTO(可以从一个实体创建多个 DTO)并仅选择所需的数据字段
例如 用户实体:有用户详细信息和好友列表 UserDetailsDTO:只需要详细信息,不需要将 1000 个朋友映射到用户......和他们的朋友...... UserFriendsDTO:我们可以有选择地获取此 DTO 的好友名称或 ID
延迟加载适用于实体,而非 DTO。
JPA 实体可以表示为 POJO 或 Proxy。
使用 EntityManager.find
给你一个 POJO:
Post post = entityManager.find(Post.class, postId);
虽然 EtityManager.getReference
方法为您提供代理:
Post post = entityManager.getReference(Post.class, postId);
POJO 已初始化其基本属性,因为执行了 SELECT 语句以获取实体。代理在创建时不会访问数据库。只有 id 是根据提供的实体标识符设置的。只有您访问代理属性,才会执行 SELECT 语句。
代理也用于默认使用 FetchType.LAZY
策略的集合(例如 @OneToMany
或 @ManyToMany
)。访问 LAZY 集合后,将执行 SELECT 语句以获取关联的集合。
现在,DTO 基于投影,因此在填充 DTO 之前执行 SELECT 语句。为此,可以说每次都是急切加载DTO。
DTO 比只读投影的实体更有效,因为您只加载您明确请求的 table 列。