JPA / Hibernate:@ManyToOne和@OneToOne关系被标记为FetchType.LAZY,而Optional = false不能在em.find()上懒惰加载?

时间:2011-10-11 23:30:35

标签: java hibernate jpa lazy-loading relationships

我有以下实体(仅显示相关映射):

@Entity
@Table(name = "PQs")
public class PQ implements Serializable
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column
    private Integer id;

    @Column
    private String name;

    @ManyToOne(fetch = FetchType.LAZY)                 // lazy XToOne
    @JoinColumn(name = "user_id", referencedColumnName = "person_id")
    private User user;

    @OneToOne(mappedBy = "pq", fetch = FetchType.LAZY) // lazy XToOne
    private Group group;

    @OneToOne(mappedBy = "pq", fetch = FetchType.LAZY) // lazy XToOne
    private Tendering tendering;

    ...
}

请注意以上评论:与其他实体有三种@XToOne关系:

用户(一个SecurityIdentity子类,其简单ID为PK,由PQ代表所有者引用):

@Entity
@Table(name = "Users")
@DiscriminatorValue(value = "user")
public class User extends SecurityIdentity
{
    @Column
    private String name;

    @OneToMany(mappedBy = "user")
    private Set<PQ> pqs = new HashSet<PQ>();

    ...
}

群组(也是一个简单ID为PK的SecurityIdentity子类,引用PQ来表示可以与该PQ交互的一组用户):

@Entity
@Table(name = "Groups")
@DiscriminatorValue(value = "group")
public class Group extends SecurityIdentity
{
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "pq_id", referencedColumnName = "id")
    private PQ pq;

    ...
}

投标

@Entity
@Table(name = "Tenderings")
public class Tendering implements Serializable
{
    @Id
    @Column(name = "pq_id", insertable = false, updatable = false)
    private Integer pqId;

    @Column(name = "external_code")
    private String externalCode;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "pq_id", referencedColumnName = "id")
    private PQ pq;

    ...
}

不要对共享ID的组和用户感到困惑,只需将它们视为简单ID即可。招标只是一个单独的文档对象(一对一)。

正如您所看到的,PQ实体上有三个@XToOne关系,如果没有设置提取类型,则会急切加载(JPA默认值)。因此,为了防止这种情况,我将所有@XToOne关系标记为FetchType.LAZY

现在使用

em.find(PQ.class, someExistingId);

我得到了Hibernate输出:

23:53:55,815 INFO  [stdout] Hibernate: select pq0_.id as id291_0_, pq0_.description as descript2_291_0_, pq0_.name as name291_0_, pq0_.submission_date as submission4_291_0_, pq0_.user_id as user5_291_0_ from PQs pq0_ where pq0_.id=?
23:53:55,818 INFO  [stdout] Hibernate: select user0_.id as id280_0_, user0_1_.identity_type_id as identity2_280_0_, user0_.is_enabled as is1_297_0_, user0_.name as name297_0_, user0_.password as password297_0_, user0_.person_id as person5_297_0_ from Users user0_ inner join SecurityIdentities user0_1_ on user0_.id=user0_1_.id where user0_.person_id=?
23:53:55,821 INFO  [stdout] Hibernate: select group0_.id as id280_0_, group0_1_.identity_type_id as identity2_280_0_, group0_.pq_id as pq2_281_0_ from Groups group0_ inner join SecurityIdentities group0_1_ on group0_.id=group0_1_.id where group0_.pq_id=?
23:53:55,823 INFO  [stdout] Hibernate: select tendering0_.pq_id as pq1_296_0_, tendering0_.binary_file as binary2_296_0_, tendering0_.customer_id as customer6_296_0_, tendering0_.description as descript3_296_0_, tendering0_.external_code as external4_296_0_, tendering0_.title as title296_0_ from Tenderings tendering0_ where tendering0_.pq_id=?

另外三个SELECT来自@XToOne关系(如网上许多地方所述)。我看来的主要来源是:

Making a OneToOne-relation lazy

如上所述,不应提取@ManyToOne关系User user

  

@ManyToOne(fetch=FetchType.LAZY)应该可以正常工作。

...这里是从 PQ 用户的关系,但 是从select user0_.id as id280_0_, ...看到的 声明...

对于其他两个Group groupTendering tendering,两个@OneToOne 反向映射,外键引用PQs表的PK(ID),从而导致PQ实体中的相同映射。

请注意,所有三种关系都不是可选的:PQ始终具有所有者(用户),并且PQ始终由招标和组实体引用。我刚才没有在上面的JPA中建模......

因此,在将optional = false添加到PQ实体的三个关系时:

@Entity
@Table(name = "PQs")
public class PQ implements Serializable
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column
    private Integer id;

    @Column
    private String name;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "user_id", referencedColumnName = "person_id")
    private User user;

    @OneToOne(mappedBy = "pq", fetch = FetchType.LAZY, optional = false)
    private Group group;

    @OneToOne(mappedBy = "pq", fetch = FetchType.LAZY, optional = false)
    private Tendering tendering;

    ...
}

...我得到以下Hibernate输出:

00:47:34,397 INFO  [stdout] Hibernate: select pq0_.id as id361_0_, pq0_.description as descript2_361_0_, pq0_.name as name361_0_, pq0_.submission_date as submission4_361_0_, pq0_.user_id as user5_361_0_ from PQs pq0_ where pq0_.id=?
00:47:34,410 INFO  [stdout] Hibernate: select user0_.id as id350_0_, user0_1_.identity_type_id as identity2_350_0_, user0_.is_enabled as is1_367_0_, user0_.name as name367_0_, user0_.password as password367_0_, user0_.person_id as person5_367_0_ from Users user0_ inner join SecurityIdentities user0_1_ on user0_.id=user0_1_.id where user0_.person_id=?
00:47:34,413 INFO  [stdout] Hibernate: select group0_.id as id350_0_, group0_1_.identity_type_id as identity2_350_0_, group0_.pq_id as pq2_351_0_ from Groups group0_ inner join SecurityIdentities group0_1_ on group0_.id=group0_1_.id where group0_.pq_id=?

请注意,我只是在PQ实体上使用optional = false,因为这是我在em.find(...)中使用的那个。 (如果这还不够,请赐教。)

我现在的问题是双重的:

  1. 为什么@ManyToOneUser实体急切地获取(因为据说这是懒惰的工作,请参阅Making a OneToOne-relation lazy)?
  2. 为什么只有与OneToOne实体的Tendering关系被取消?是因为Tendering实体引用PQ的PK列作为PK本身(@Id中的Tendering),Group实体没有(与PQ的常规关系) PK)?
  3. 怎么了?如何使这些非可选关系变得懒惰? (没有代码检测或其他黑客,只是简单的注释......)

    我知道LAZY的事情只是提示JPA提供者做一些关于延迟加载的事情,但是在这种情况下看起来好像其他错误(因为它的一部分正在工作)。

    PS:我正在使用Hibernate 4.0 BETA,JBoss 7.0.0.Final附带的版本以及JPA注释(以上都是JPA 1.0兼容)。

4 个答案:

答案 0 :(得分:2)

您好我不确定JPA,但对于many-to-oneone-to-one映射,支持hibernate的延迟值为proxyno-proxyfalse其中虚假是默认的。检查DTD的这一部分

lazy="proxy|no-proxy|false"

您可以查看此Link。我认为这可以解决你的第一个问题。

答案 1 :(得分:2)

使用hibernate注释和jpa注释之间存在差异,据我所知,除了某些情况外,hibernate默认是延迟加载的。这是一个快速讨论:

http://community.jboss.org/wiki/AShortPrimerOnFetchingStrategies

答案 2 :(得分:0)

* ToOne关系意味着在对象初始化之后必须有(代理)bean,一旦以任何方式访问它就会触发select(你看到它)你确定你对强制加载的对象什么也不做?

答案 3 :(得分:0)

您好Kawu显示额外的SELECT,因为它将为所有涉及的实体执行SELECT,尝试使用FetchType.LAZY作为默认的一对多,并且在大多数情况下使用FETCH JOIN来获得结果。

我希望能帮助您或需要此信息的人