首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >双向EagerFetch @oneTomany映射工作

双向EagerFetch @oneTomany映射工作
EN

Stack Overflow用户
提问于 2022-11-09 13:02:28
回答 1查看 25关注 0票数 0

我在DB中有3个表,在Java应用程序中分别有3个JPA实体。

代码语言:javascript
复制
@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);

}

我的用例

在某种类型的欺诈中,我想遍历所有从这类欺诈中触发的行为,并对它们采取行动。

存取码

代码语言:javascript
复制
Fraud fraud = fraudRepository.findByFraudTypeAndFraudValue("Type", "Value");
log.info(fraud.getFraudActions().get(0).getAction());  

当我运行上面的代码时,一切正常。我也得到了fraudfraudActions关联,没有任何错误。

我的印象是,由于两个实体FraudFraudActionEntity都在急切地相互取回,所以它应该会产生一些错误,比如循环提取/无限获取循环,但是它没有!

为什么起作用了?什么时候会出现类似循环取错或无限取环错误这样的错误?如果它确实给出了循环获取错误,那么我们是否可以在@ManyToOne @ManyToOne端使用延迟获取来修复它,如下所示:

代码语言:javascript
复制
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "fraud_id")
private Fraud fraud;
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-11-09 19:36:14

这些是JPA注释和循环,提供者知道这些注释和周期,因此知道如何处理JPA--规范中并没有详细说明,但它们的工作原理几乎是正确的。

你只有一个周期,双向欺诈-欺诈-实体关系。JPA提供程序已经需要某种级别的实体缓存来进行实体标识管理。如果你:

代码语言:javascript
复制
Fraud fraudA = em.find(1, Fraud.class);
Fraud fraudAPrime = em.find(1, Fraud.class);
assertTrue(fraudA == fraudAPrime)

JPA要求fraudA和fraudAPrime必须是同一个对象实例。

JPA要求引用(FKs)只引用一个实体主键,这使得缓存查找来构建这些引用是可管理的。因此,在构建欺诈和获取FraudActionEntity时,它可以检查每个缓存,如果已经存在则只返回该实例。同样,如果它正在构建一个FraudActionEntity实例-它可以检查FK值引用的欺诈是否已经存在,并从缓存返回if,而不必从DB构建它。这种短路存在双向和循环引用的问题,并确保在遍历从上下文读取的任何对象图时,无论如何遍历或获取“fraudA”实例,都必须得到它。对象标识是JPA的基础。

JPA允许提供程序处理大型对象图的另一种方法是懒惰:如果它不需要获取一些东西,这也解决了这个问题。这可以帮助循环,但更多的目标是修剪大型对象图。如果您的操作有1:M到FraudActionEntity,那么阅读欺诈可能是个问题。您只是没有映射关系,在获取欺诈时对图形进行修剪,类似于懒散,但以后没有钩子来获取它(您必须用action方法编写自己的查找)。

当涉及到其他形式的序列化时,通常会出现周期问题。REST/Spring等类似程序的共同点是,这些实体实例将被序列化为JSON。这些序列化工具(Jackson是常见的)不是JPA实现,因此不知道甚至不查看JPA注释。它们会影响这个循环对象引用的问题,您可以很容易地在这里找到有关如何处理这个问题和解决方案的问题和解决方案--简而言之,这个序列化级别需要查看和处理,解决方案可能与您需要从数据库中读取的模型非常不同。它们没有内置相同的实体缓存机制,因此应该根据应用程序的性能需求和需求进行独立的调整。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74375315

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档