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

41ik7eoe  于 12个月前  发布在  Spring
关注(0)|答案(2)|浏览(175)

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

用户实体

@Entity
@Table(name = "users")
@Data
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;
    @Column(name = "username", length = 50)
    private String username;
    @Column(name = "email")
    private String email;
    @Column(name = "password")
    private String password;
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "user_friends" , joinColumns = @JoinColumn(name = "user_id") , inverseJoinColumns = @JoinColumn(name = "friend_id"))
    @OnDelete(action = OnDeleteAction.CASCADE)
    private Set<User> friends = new HashSet<>();

}

字符串

用户服务

@Service
@Transactional
public class UserService implements ICrudService<User> {
    @Autowired
    private UserRepository repository;

    @Override
    @Transactional
    public List<User> findAll() {
        return repository.findAll();
    }

    @Override
    @Transactional
    public User findById(Long id) throws Exception {
        return repository.findById(id).orElseThrow(() -> new Exception("Kullanici Bulunamadi"));
    }

    @Override
    @Transactional
    public User create(User user) {
        return repository.save(user);
    }

    @Override
    public void delete(Long id) {
        repository.deleteById(id);
    }
}

用户控制器

@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/all")
    public List<User> getUsers(){
        return userService.findAll();
    }

    @GetMapping("/{userId}")
    public User getUserById(@PathVariable Long userId) throws Exception {
        return userService.findById(userId);
    }

    @PostMapping
    public User saveUser(@RequestBody User user){
        return userService.create(user);
    }

    @DeleteMapping("/{userId}")
    public void deleteUserById(@PathVariable Long userId){
        userService.delete(userId);
    }
}


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

输出

[
    {
        "id": 1,
        "username": "testUser",
        "email": "[email protected]",
        "password": "verystrongpasword",
        "friends": []
    }
]

这是休眠sql格式

Hibernate: 
    select
        u1_0.id,
        u1_0.email,
        u1_0.password,
        u1_0.username 
    from
        users u1_0
Hibernate: 
    select
        f1_0.user_id,
        f1_1.id,
        f1_1.email,
        f1_1.password,
        f1_1.username 
    from
        user_friends f1_0 
    join
        users f1_1 
            on f1_1.id=f1_0.friend_id 
    where
        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排除所有惰性和双向字段。在您的情况下,类似于下一个:

@Entity
@Table(name = "users")
@Data
@ToString
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;
    @Column(name = "username", length = 50)
    private String username;
    @Column(name = "email")
    private String email;
    @Column(name = "password")
    private String password;
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "user_friends" , joinColumns = @JoinColumn(name = "user_id") , inverseJoinColumns = @JoinColumn(name = "friend_id"))
    @OnDelete(action = OnDeleteAction.CASCADE)
    @ToString.Exclude
    private Set<User> friends = new HashSet<>();

}

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

相关问题