【问题标题】:One to one relationship doesn't work一对一的关系不起作用
【发布时间】:2018-08-06 09:56:29
【问题描述】:

Hibernate 版本 - 5.3.4.Final,mysql-connector 版本 - 8.0.12

我在帖子和帖子内容之间有一个@OneToOne 关系:

帖子:

@Entity
@Table(name = "postsInfo")
public class PostsInfo {


    private long postId;
    private String title;
    private java.util.Date createDate;
    private Integer views;
    private Collection<Tags> tagsPost;
    private PostContent postContent;
    private PostImage postImage;
    private UserInfo userInfo;
    private List<PostsComments> postsComments;

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "post_id", unique = true, nullable = false)
    public long getPostId() {
        return postId;
    }

    @Basic
    @Column(name = "title", nullable = false)
    public String getTitle() {
        return title;
    }

    @Basic
    @Column(name = "createDate", nullable = false)
    public java.util.Date getCreateDate() {
        return createDate;
    }

    @Basic
    @Column(name = "views")
    public Integer getViews() {
        return views;
    }

    public PostsInfo(){}

    public PostsInfo(String title, List<Tags> tagsPost) {
        this.title = title;
        this.tagsPost = tagsPost;
        this.createDate = new Date();
    }

    @Fetch(FetchMode.SUBSELECT)
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "PostsTags",
            joinColumns = @JoinColumn(name = "post_id"),
            inverseJoinColumns = @JoinColumn(name = "tag_id"))
    public Collection<Tags> getTagsPost() {
        return tagsPost;
    }

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "postsInfo", fetch = FetchType.LAZY, optional = false)
    public PostContent getPostContent() {
        return postContent;
    }

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "postsInfo", orphanRemoval = true, fetch = FetchType.EAGER)
    public PostImage getPostImage() {
        return this.postImage;
    }

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "user_id", nullable = false)
    public UserInfo getUserInfo() {
        return userInfo;
    }

    @Cascade(org.hibernate.annotations.CascadeType.ALL)
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "postsInfo")
    public List<PostsComments> getPostsComments() {
        return postsComments;
    }
}

发布内容:

   @Entity
@Table(name = "postContent")
public class PostContent {
    private long postId;
    private String content;
    private String subtitle;
    private List<PostInsideImages> postInsideImages;
    private PostsInfo postsInfo;

    @GenericGenerator(name = "generator", strategy = "foreign",
    parameters = @org.hibernate.annotations.Parameter(name = "property", value = "postsInfo"))
    @Id @GeneratedValue(generator = "generator")
    @Column(name = "post_id")
    public long getPostId() {
        return postId;
    }

    @Basic
    @Column(name = "content")
    public String getContent() {
        return content;
    }

    @Basic
    @Column(name = "subtitle")
    public String getSubtitle() {
        return subtitle;
    }

    public PostContent(){}

    public PostContent(String subtitle ,String content) {
        this.content = content;
        this.subtitle = subtitle;
    }

    public PostContent(String subtitle, String content, List<PostInsideImages> postInsideImages) {
        this.content = content;
        this.subtitle = subtitle;
        this.postInsideImages = postInsideImages;
    }

    @OneToMany( cascade = CascadeType.ALL, mappedBy = "postContent")
    @LazyCollection(LazyCollectionOption.FALSE)
    public List<PostInsideImages> getPostInsideImages() {
        return postInsideImages;
    }

    @OneToOne(fetch = FetchType.LAZY, optional = false)
    @PrimaryKeyJoinColumn
    public PostsInfo getPostsInfo() {
        return postsInfo;
    }
}

我一直试图让 PostContent 的加载变得懒惰,但没有任何效果。

我添加到@OneToOne 关系 fetch = FetchType.LAZY, optional = false,

我在 hibernate.cfg.xml 中添加了这个属性:

<property name="hibernate.enhancer.enableLazyInitialization">true</property>

还有这个 Maven 插件:

<plugin>
                <groupId>org.hibernate.orm.tooling</groupId>
                <artifactId>hibernate-enhance-maven-plugin</artifactId>
                <version>5.3.4.Final</version>
                <executions>
                    <execution>
                        <configuration>
                            <failOnError>true</failOnError>
                            <enableLazyInitialization>true</enableLazyInitialization>
                        </configuration>
                        <goals>
                            <goal>enhance</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

启用字节码增强,

添加@LazyToOne(LazyToOneOption.NO_PROXY)

我尝试更改休眠版本(5.2、5.1.10、5.3.3、5.3.1),但仍然休眠加载帖子内容急切。

我的发帖代码:

@Override
public PostsInfo getCommonPost(long id){
    return session.find(PostsInfo.class, id);
}

休眠sql:

    Hibernate: select postsinfo0_.post_id as post_id1_9_0_, postsinfo0_.createDate as createDa2_9_0_, postsinfo0_.title as title3_9_0_, postsinfo0_.user_id as user_id5_9_0_, postsinfo0_.views as views4_9_0_, postimage1_.post_id as post_id1_6_1_, postimage1_.image_l as image_l2_6_1_, postimage1_.image_m as image_m3_6_1_, postimage1_.image_s as image_s4_6_1_ from postsInfo postsinfo0_ left outer join postImage postimage1_ on postsinfo0_.post_id=postimage1_.post_id where postsinfo0_.post_id=?
Hibernate: select postconten0_.post_id as post_id1_5_0_, postconten0_.content as content2_5_0_, postconten0_.subtitle as subtitle3_5_0_ from postContent postconten0_ where postconten0_.post_id=?
Hibernate: select postinside0_.post_id as post_id3_7_0_, postinside0_.image_id as image_id1_7_0_, postinside0_.image_id as image_id1_7_1_, postinside0_.image as image2_7_1_, postinside0_.post_id as post_id3_7_1_ from postInsideImages postinside0_ where postinside0_.post_id=?
Hibernate: select tagspost0_.post_id as post_id1_10_0_, tagspost0_.tag_id as tag_id2_10_0_, tags1_.tag_id as tag_id1_15_1_, tags1_.description as descript2_15_1_, tags1_.name as name3_15_1_ from PostsTags tagspost0_ inner join Tags tags1_ on tagspost0_.tag_id=tags1_.tag_id where tagspost0_.post_id=?

我可以做些什么来获得延迟加载?

【问题讨论】:

  • 我会避免完全使用一对一 - 它们往往会使数据结构复杂化,有时会产生性能问题。如果您正在使用 Spring 的 DTO/DAO 系统,您可以稍后将数据分离到不同的类中。
  • @Kilves,现在我正在使用 java ee 堆栈,如果你建议如何最好地组织数据,那么我很乐意提供任何帮助
  • 我接受@OneToOne 无论你做什么都不会偷懒。我最终使用了投影。
  • @user2215545,如果您的意思是从帖子 p 中选择新的 project.dto.post(p.id, p.name),那么我遇到了如何加载集合的问题

标签: java hibernate jakarta-ee orm


【解决方案1】:

@Danil Eltsov,这意味着您对该相关集合进行另一个查询。无论如何,延迟加载都会生成另一个查询。

【讨论】:

  • 如果我需要收集这些帖子 (n),那么我将不得不为每个帖子提出 n 个请求?
  • 这意味着您对每个帖子都提出请求。如您所见,Hibernate 为您生成了 4 个查询,其中一个具有连接,我认为这是您要避免的。默认情况下,代表集合的 OneToMany 相关实体将发出急切加载。然后 Hibernate 会在您需要时发出查询。使用投影,您可以手动完成,因此您可以优化查询并避免您可能不需要的休眠生成查询。
【解决方案2】:

您的数据库中有设计气味。因为您没有与父表 PK 共享子表 PK。一对一的公会永远共享PK。在您的情况下,您的 PostContent 类的 postId 应仅由 PostsInfo 类的 postId 映射。但是在 PostContent 中,对于 PostsInfo,您有单独的 PK 和 FK,这对于一对一的关系来说应该是相同的,这也是 hibernate 所提倡的。因为如果您有单独的 FK 和 PK,那么一个 PostsInfo 可能有多个 PostContent。 请通过以下链接,因为其中解释的场景与您的场景非常相似。

https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/

【讨论】:

  • 我正确理解要接收帖子的内容必须发出第二个请求?(然后我可以使用继承加入策略,但我需要1个请求)
猜你喜欢
  • 2020-10-16
  • 1970-01-01
  • 2016-09-07
  • 1970-01-01
  • 1970-01-01
  • 2014-05-11
  • 2020-03-14
相关资源
最近更新 更多