spring-data-jpa 双向EagerFetch @oneTomanyMap工作正常

ryevplcw  于 2022-11-10  发布在  Spring
关注(0)|答案(1)|浏览(124)

我在数据库中有3个表,在Java应用程序中有3个JPA实体。

@Data
@Entity
public class Fraud {

    @Id
    @Column(name = "id")
    private Integer id;

    @Column(name = "fraud_type")
    private String fraudType;

    @Column(name = "fraud_value")
    private String fraudValue;

    @OneToMany(mappedBy = "fraud", fetch = FetchType.EAGER)
    private List<FraudActionEntity> fraudActions;

}

@Data
@Entity
public class FraudActionEntity {

    @Id
    @Column(name = "id")
    private Integer id;

    @ManyToOne
    @JoinColumn(name = "fraud_id")
    private Fraud fraud;

    @ManyToOne
    @JoinColumn(name = "action_id")
    private Action action;

    @Column(name = "enabled")
    private Boolean enabled;
}

@Data
@Entity
public class Action {

    @Id
    @Column(name = "id")
    private Integer id;

    @Column(name = "attribute_key")
    private String attributeKey;

    @Column(name = "attribute_value")
    private String attributeValue;

}

@Repository
public interface FraudRepository extends JpaRepository<Fraud, Integer> {

    public Fraud findByFraudTypeAndFraudValue(String fraudType, String fraudValue);

}
我的用例

对于某种类型的欺诈,我希望遍历该类型欺诈触发的所有操作并对其采取行动。

访问代码
Fraud fraud = fraudRepository.findByFraudTypeAndFraudValue("Type", "Value");
log.info(fraud.getFraudActions().get(0).getAction());

当我运行上面的代码时,一切正常。我也得到了fraudfraudActions的关联,没有得到任何错误。
我的印象是,由于两个实体FraudFraudActionEntity都在急切地获取对方,所以它应该会给予一些错误,如循环获取/无限获取循环,但它没有!
为什么它能工作?什么时候会给予循环提取错误或无限提取循环错误?如果它确实出现循环提取错误,我们可以在@ManyToOne端使用lazy fetch来修复它吗,如下所示:

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "fraud_id")
private Fraud fraud;
ymdaylpp

ymdaylpp1#

这些是JPA注解和循环,提供者知道它们,因此知道如何处理它们--规范中没有详细说明如何处理,但它们基本上是工作的。
您只有一个循环,即双向Fraud-FraudActionEntity关系。JPA提供程序已经需要某种级别的实体缓存来进行实体身份管理。如果您执行:

Fraud fraudA = em.find(1, Fraud.class);
Fraud fraudAPrime = em.find(1, Fraud.class);
assertTrue(fraudA == fraudAPrime)

JPA要求fraudA和fraudAPrime必须是同一个对象示例。
JPA要求引用(FK)仅引用实体主键,从而使构建这些引用的缓存查找可管理。因此,在构建欺诈并获取FraudActionEntity时,它可以检查每个示例该高速缓存,如果该示例已经存在,则只返回该示例。如果它正在构建FraudActionEntity示例,则情况相同-它可以检查FK值所引用的欺诈是否已经存在,并该高速缓存中返回,而不必从DB中构建它。这解决了双向和循环引用的问题,并确保在遍历从上下文读取的任何对象图时,无论如何遍历或获取该图,都只获取'fraudA'示例。
Lazy是JPA允许提供者处理大型对象图的另一种方法:如果它不需要获取某些东西,也可以解决这个问题。这可以帮助处理循环,但更多的是针对修剪大的对象图。如果你让Actions与FraudActionEntity的比例为1:M,那么阅读一个Fraud可能会有问题。你只是没有Map关系,在获取fraud时修剪图,就像lazy做的那样,但没有钩子来稍后获取它(你必须编写你自己的find by action方法)。
循环的问题通常发生在涉及其他形式的序列化时。REST/Spring等的共同点是这些实体示例将被序列化为JSON。这些序列化工具(Jackson是常见的)不是JPA实现,所以不知道甚至不看JPA注解。它们是这个循环对象引用遇到问题的原因,并且您可以在这里轻松地找到有关如何处理的问题和解决方案--简而言之,需要查看和处理这一级别的序列化,解决方案可能与您需要从数据库读取的模型有很大不同,它们没有内置相同的实体缓存机制,因此应根据应用程序性能需要和要求进行独立调整。

相关问题