leo*_*eon 512 java orm hibernate jpa java-persistence-api
我是Java Persistence API和Hibernate的新手.
Java Persistence API FetchType.LAZY
和之间的区别是什么FetchType.EAGER
?
Lam*_*bda 984
有时你有两个实体,它们之间有关系.例如,您可能有一个名为University的实体和另一个名为Student的实体.
大学实体可能有一些基本属性,如身份证,姓名,地址等,以及一个名为学生的财产:
public class University {
private String id;
private String name;
private String address;
private List<Student> students;
// setters and getters
}
Run Code Online (Sandbox Code Playgroud)
现在,当您从数据库加载大学时,JPA会为您加载其ID,名称和地址字段.但是对于学生来说,您有两种选择:将其与其他字段一起加载(即热切地)或者在您调用大学的getStudents()方法时按需加载(即懒惰).
当一所大学有很多学生时,在不需要的时候加载所有学生并不高效.因此,在这种情况下,您可以声明您希望学生在实际需要时加载.这称为延迟加载.
unb*_*eli 265
基本上,
LAZY = fetch when needed
EAGER = fetch immediately
Run Code Online (Sandbox Code Playgroud)
Boz*_*zho 64
EAGER
加载集合意味着在获取父级时完全获取它们.因此,如果你拥有Course
它 List<Student>
,那么所有的学生都会在获取时从数据库中Course
获取.
LAZY
另一方面,意味着List
只有在您尝试访问它们时才会获取内容.例如,通过呼叫course.getStudents().iterator()
.调用任何访问方法List
将启动对数据库的调用以检索元素.这是通过围绕List
(或Set
)创建代理来实现的.所以对于你的懒惰集合,具体类型不是ArrayList
和HashSet
,但是PersistentSet
和PersistentList
(或PersistentBag
)
Kyu*_*Min 16
我可以考虑性能和内存利用率.一个很大的区别是EAGER获取策略允许在没有会话的情况下使用获取的数据对象.为什么?
当会话连接时,当对象中的标记数据急切时,将获取所有数据.但是,在延迟加载策略的情况下,如果会话断开连接(session.close()
语句之后),则延迟加载标记的对象不会检索数据.所有这些都可以通过hibernate代理来完成.急切策略可让数据在关闭会话后仍然可用.
小智 11
默认情况下,对于所有集合和映射对象,提取规则是FetchType.LAZY
,对于其他实例,它遵循FetchType.EAGER
策略.
简言之,@OneToMany
而@ManyToMany
关系不implicictly获取相关对象(采集和地图),但检索操作通过现场级联@OneToOne
和@ManyToOne
的.
JDG*_*ide 10
据我所知,两种类型的提取都取决于您的要求.
FetchType.LAZY
按需(即我们需要数据时).
FetchType.EAGER
是即时的(即在我们的要求到来之前,我们不必要地获取记录)
Ebr*_*ee' 10
我想将这条注释添加到上面所说的内容中。
假设您将 Spring(MVC 和数据)与这个简单的架构师一起使用:
控制器 <-> 服务 <-> 存储库
如果你想返回一些数据到前端,如果你使用FetchType.LAZY
,你会LazyInitializationException
在将数据返回到控制器方法后得到一个 ,因为会话在 Service 中关闭,所以JSON Mapper Object
无法获取数据。
根据设计、性能和开发人员的不同,有两种常见的选项可以解决此问题:
FetchType.EAGER
或任何其他反模式解决方案,以便会话在控制器方法中仍然有效,但这些解决方案会影响性能。FetchType.LAZY
与映射器(如)一起使用,将数据从另一个数据对象MapStruct
传输到另一个数据对象,然后将其发送回控制器,因此即使会话关闭也不会出现异常。Entity
DTO
有一个简单的例子:
@RestController
@RequestMapping("/api")
public class UserResource {
@GetMapping("/users")
public Page<UserDTO> getAllUsers(Pageable pageable) {
return userService.getAllUsers(pageable);
}
}
Run Code Online (Sandbox Code Playgroud)
@Service
@Transactional
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Transactional(readOnly = true)
public Page<UserDTO> getAllUsers(Pageable pageable) {
return userRepository.findAll(pageable).map(UserDTO::new);
}
}
Run Code Online (Sandbox Code Playgroud)
@Repository
public interface UserRepository extends JpaRepository<User, String> {
Page<User> findAll(Pageable pageable);
}
Run Code Online (Sandbox Code Playgroud)
public class UserDTO {
private Long id;
private String firstName;
private String lastName;
private String email;
private Set<String> addresses;
public UserDTO() {
// Empty constructor needed for Jackson.
}
public UserDTO(User user) {
this.id = user.getId();
this.firstName = user.getFirstName();
this.lastName = user.getLastName();
this.email = user.getEmail();
this.addresses = user.getAddresses().stream()
.map(Address::getAddress)
.collect(Collectors.toSet());
}
// Getters, setters, equals, and hashCode
}
Run Code Online (Sandbox Code Playgroud)
@Entity
@Table(name = "user")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column
private String firstName;
@Column
private String lastName;
@Column(unique = true)
private String email;
@OneToMany(mappedBy = "address", fetch = FetchType.LAZY)
private Set<Address> addresses = new HashSet<>();
// Getters, setters, equals, and hashCode
}
Run Code Online (Sandbox Code Playgroud)
@Entity
@Table(name = "address")
public class Address implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column
private String address;
@ManyToOne
@JsonIgnoreProperties(value = "addresses", allowSetters = true)
private User user;
// Getters, setters, equals, and hashCode
}
Run Code Online (Sandbox Code Playgroud)
双方FetchType.LAZY
并FetchType.EAGER
用来定义默认提取计划.
不幸的是,您只能覆盖LAZY抓取的默认抓取计划.EAGER提取不太灵活,可能导致许多性能问题.
我的建议是限制使你的协会成为EAGER的冲动,因为抓取是一个查询时间的责任.因此,您的所有查询都应该使用fetch指令来仅检索当前业务案例所需的内容.
该Lazy
提取类型默认情况下由Hibernate选择,除非你明确地标记Eager
取型。为了更准确和简洁,差异可以说明如下。
FetchType.LAZY
= 这不会加载关系,除非您通过 getter 方法调用它。
FetchType.EAGER
= 这将加载所有关系。
这两种获取类型的优缺点。
Lazy initialization
通过避免不必要的计算和减少内存需求来提高性能。
Eager initialization
占用内存较多,处理速度较慢。
话虽如此,根据情况可以使用这些初始化中的任何一个。
JOIN
有什么大不了的简单来说:
假设我们有一个名为 an 的类User
,另一个名为 an 的类Address
,并且假设每个用户都有一个或多个表示关系(一对多)的地址,如果您执行:
FetchType.LAZY
执行 sql 命令就像没有join
:
SELECT * FROM users
Run Code Online (Sandbox Code Playgroud)
FetchType.EAGER
执行 sql 命令,如下所示join
:
SELECT * FROM users u join address a on a.user_id = u.user_id
Run Code Online (Sandbox Code Playgroud)
注意:上述查询只是为了向您澄清图像,但 Hibernate 框架在实际中执行与上述查询类似的查询。
哪种获取类型更好?
如果您使用的是Spring Boot 框架,请提交application.properties
文件并添加以下命令以了解到底发生了什么。
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
443474 次 |
最近记录: |