【问题标题】:LazyInitializationException when accessing LAZY collection on User访问用户上的 LAZY 集合时出现 LazyInitializationException
【发布时间】:2019-06-16 20:59:08
【问题描述】:

我有一个包含延迟加载对象集合的用户类。

class User {
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @Getter
    @Column(nullable = false)
    private List<Wallet> wallets= new ArrayList<>();
}

现在我还有一个 Transaction 类,其中包含对用户钱包的引用。

class Transaction {
        @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
        @JoinColumn(name = "senderWallet", referencedColumnName = "id")
        private Wallet senderWallet;
}

现在我创建了一个服务来获取给定用户的交易:

@Transactional
public List<Transaction> getTransactionsForUser(User user) {
    List<Wallet> wallets = user.getWallets();
    List<Transaction> transactions = new ArrayList<>();

    for (Wallet wallet : wallets) {
        transactions.addAll(transactionRepository.findBySenderWallet(wallet));
    }

    return transactions;
}

在控制器中,我正在获取当前登录的用户,如下所示:

User user = ((UserPrincipal) authentication.getPrincipal()).getUser();

然后,我调用服务:

List<Transaction> transactions = transactionService.getTransactionsForUser(user);

这会引发 LazyInitializationException。这里有什么解决方法?

【问题讨论】:

    标签: java spring hibernate spring-boot jpa


    【解决方案1】:

    1) 我认为您的@OneToMany 应该定义mappedBy

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="user")
    @Getter
    @Column(nullable = false)
    private List<Wallet> wallets= new ArrayList<>();
    

    2)您正在传递一个实体User,该实体已在似乎已关闭的不同事务上下文中获取。

    在服务方法中,您应该在继续之前执行该实体的合并。 Srping Data Jpa save 方法已实现合并,因此调用就足够了:

    @Transactional
    public List<Transaction> getTransactionsForUser(User user) {
        userRepository.save(user);  // Add this <---
    
        List<Wallet> wallets = user.getWallets();
        List<Transaction> transactions = new ArrayList<>();
    
        for (Wallet wallet : wallets) {
            transactions.addAll(transactionRepository.findBySenderWallet(wallet));
        }
    
        return transactions;
    } 
    

    【讨论】:

    • 1 背后的原因是什么?用户是关系的所有者。 2)这就是我的猜测,但每次都这样做似乎违反直觉。有没有不同的方法来做我想要实现的目标? (在设计/架构方面 - 可能会在服务中添加一个新方法,该方法将在服务中获取登录用户,而不是在控制器中获取它)
    • 1 的原因是你已经定义了一个bidirectional 映射但是没有声明一个owning 实体。因此,您的架构将同时具有连接表和不正确的外键。
    • 除此之外,您还可以在 OneToMany 上使用 JoinColumn 或 JoinTable。拥有的实体上不存在这样的非列。
    猜你喜欢
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 2015-07-18
    • 2013-10-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多