spring Fetch类型被设置为lazy,但它仍然会休眠发送第二个请求

41ik7eoe  于 2024-01-05  发布在  Spring
关注(0)|答案(2)|浏览(258)

虽然fetch类型是懒惰的,但出于某种原因,hibernate会发送第二个请求并获取懒惰的请求。我已经处理这个问题几天了,出于某种原因,我不明白。我在互联网上尝试了一些方法,但不幸的是,我无法修复它,如果你能帮助我看看我的代码,我会非常感激。

用户实体

  1. @Entity
  2. @Table(name = "users")
  3. @Data
  4. public class User {
  5. @Id
  6. @GeneratedValue(strategy = GenerationType.SEQUENCE)
  7. private Long id;
  8. @Column(name = "username", length = 50)
  9. private String username;
  10. @Column(name = "email")
  11. private String email;
  12. @Column(name = "password")
  13. private String password;
  14. @ManyToMany(fetch = FetchType.LAZY)
  15. @JoinTable(name = "user_friends" , joinColumns = @JoinColumn(name = "user_id") , inverseJoinColumns = @JoinColumn(name = "friend_id"))
  16. @OnDelete(action = OnDeleteAction.CASCADE)
  17. private Set<User> friends = new HashSet<>();
  18. }

字符串

用户服务

  1. @Service
  2. @Transactional
  3. public class UserService implements ICrudService<User> {
  4. @Autowired
  5. private UserRepository repository;
  6. @Override
  7. @Transactional
  8. public List<User> findAll() {
  9. return repository.findAll();
  10. }
  11. @Override
  12. @Transactional
  13. public User findById(Long id) throws Exception {
  14. return repository.findById(id).orElseThrow(() -> new Exception("Kullanici Bulunamadi"));
  15. }
  16. @Override
  17. @Transactional
  18. public User create(User user) {
  19. return repository.save(user);
  20. }
  21. @Override
  22. public void delete(Long id) {
  23. repository.deleteById(id);
  24. }
  25. }

用户控制器

  1. @RestController
  2. @RequestMapping("/users")
  3. public class UserController {
  4. @Autowired
  5. private UserService userService;
  6. @GetMapping("/all")
  7. public List<User> getUsers(){
  8. return userService.findAll();
  9. }
  10. @GetMapping("/{userId}")
  11. public User getUserById(@PathVariable Long userId) throws Exception {
  12. return userService.findById(userId);
  13. }
  14. @PostMapping
  15. public User saveUser(@RequestBody User user){
  16. return userService.create(user);
  17. }
  18. @DeleteMapping("/{userId}")
  19. public void deleteUserById(@PathVariable Long userId){
  20. userService.delete(userId);
  21. }
  22. }


我使用JpaReository作为服务中的存储库
“/users/all”的输出如下所示

输出

  1. [
  2. {
  3. "id": 1,
  4. "username": "testUser",
  5. "email": "[email protected]",
  6. "password": "verystrongpasword",
  7. "friends": []
  8. }
  9. ]

这是休眠sql格式

  1. Hibernate:
  2. select
  3. u1_0.id,
  4. u1_0.email,
  5. u1_0.password,
  6. u1_0.username
  7. from
  8. users u1_0
  9. Hibernate:
  10. select
  11. f1_0.user_id,
  12. f1_1.id,
  13. f1_1.email,
  14. f1_1.password,
  15. f1_1.username
  16. from
  17. user_friends f1_0
  18. join
  19. users f1_1
  20. on f1_1.id=f1_0.friend_id
  21. where
  22. f1_0.user_id=?

cnh2zyt3

cnh2zyt31#

当属性的fetch type为Lazy时,当属性的getter被调用时,数据将按需检索。当响应被发送时,User被序列化为json,json库通常使用getters -getFriends()被底层库反射调用。
解决方案(以及良好的实践)是使用DTO作为响应/请求,而不是实体。

wqnecbli

wqnecbli2#

这个问题是由Lombok@Data注解触发的,因为在后台它使用@ToString,默认情况下使用class的所有字段来创建它。
有两种可能的解决方案:
1.创建你自己的toString()方法,然后Lombok会回退生成一个toString。
2.添加@ToString注解,并使用@ToString.Exclude排除所有惰性和双向字段。在您的情况下,类似于下一个:

  1. @Entity
  2. @Table(name = "users")
  3. @Data
  4. @ToString
  5. public class User {
  6. @Id
  7. @GeneratedValue(strategy = GenerationType.SEQUENCE)
  8. private Long id;
  9. @Column(name = "username", length = 50)
  10. private String username;
  11. @Column(name = "email")
  12. private String email;
  13. @Column(name = "password")
  14. private String password;
  15. @ManyToMany(fetch = FetchType.LAZY)
  16. @JoinTable(name = "user_friends" , joinColumns = @JoinColumn(name = "user_id") , inverseJoinColumns = @JoinColumn(name = "friend_id"))
  17. @OnDelete(action = OnDeleteAction.CASCADE)
  18. @ToString.Exclude
  19. private Set<User> friends = new HashSet<>();
  20. }

字符串
关于Lombok-Data-Ojects-Arent-Entities和其他案例的更深入的细节,你可以找到Marten代努姆的一篇好文章。

展开查看全部

相关问题