One-to-many
The one-to-many table relationship looks like this:

In a relational database system, a one-to-many table relationship associates two tables based on a Foreign Key column in the child table referencing the Primary Key of one record in the parent table.
In the table diagram above, the post_id column in the post_comment table has a Foreign Key relationship with the post table id Primary Key column:
    ALTER TABLE
        post_comment
    ADD CONSTRAINT
        fk_post_comment_post_id
    FOREIGN KEY (post_id) REFERENCES post
@ManyToOne annotation
In JPA, the best way to map the one-to-many table relationship is to use the @ManyToOne annotation.
In our case, the PostComment child entity  maps the post_id Foreign Key column using the @ManyToOne annotation:
    @Entity(name = "PostComment")
    @Table(name = "post_comment")
    public class PostComment {
    
        @Id
        @GeneratedValue
        private Long id;
    
        private String review;
    
        @ManyToOne(fetch = FetchType.LAZY)
        private Post post;
        
    }
Using the JPA @OneToMany annotation
Just because you have the option of using the @OneToMany annotation, it doesn't mean it should be the default option for all the one-to-many database relationships.
The problem with JPA collections is that we can only use them when their element count is rather low.
The best way to map a @OneToMany association is to rely on the @ManyToOne side to propagate all entity state changes:
    @Entity(name = "Post")
    @Table(name = "post")
    public class Post {
    
        @Id
        @GeneratedValue
        private Long id;
    
        private String title;
    
        @OneToMany(
            mappedBy = "post", 
            cascade = CascadeType.ALL, 
            orphanRemoval = true
        )
        private List<PostComment> comments = new ArrayList<>();
    
        //Constructors, getters and setters removed for brevity
    
        public void addComment(PostComment comment) {
            comments.add(comment);
            comment.setPost(this);
        }
    
        public void removeComment(PostComment comment) {
            comments.remove(comment);
            comment.setPost(null);
        }
    }
The parent Post entity features two utility methods (e.g. addComment and removeComment) which are used to synchronize both sides of the bidirectional association.
You should provide these methods whenever you are working with a bidirectional association as, otherwise, you risk very subtle state propagation issues.
The unidirectional @OneToMany association is to be avoided as it's less efficient than using @ManyToOne or the bidirectional @OneToMany association.
One-to-one
The one-to-one table relationship looks as follows:

In a relational database system, a one-to-one table relationship links two tables based on a Primary Key column in the child which is also a Foreign Key referencing the Primary Key of the parent table row.
Therefore, we can say that the child table shares the Primary Key with the parent table.
In the table diagram above, the id column in the post_details table has also a Foreign Key relationship with the post table id Primary Key column:
    ALTER TABLE
        post_details
    ADD CONSTRAINT
        fk_post_details_id
    FOREIGN KEY (id) REFERENCES post
Using the JPA @OneToOne with @MapsId annotations
The best way to map a @OneToOne relationship is to use @MapsId. This way, you don't even need a bidirectional association since you can always fetch the PostDetails entity by using the Post entity identifier.
The mapping looks like this:
@Entity(name = "PostDetails")
@Table(name = "post_details")
public class PostDetails {
    @Id
    private Long id;
    @Column(name = "created_on")
    private Date createdOn;
    @Column(name = "created_by")
    private String createdBy;
    @OneToOne(fetch = FetchType.LAZY)
    @MapsId
    @JoinColumn(name = "id")
    private Post post;
    public PostDetails() {}
    public PostDetails(String createdBy) {
        createdOn = new Date();
        this.createdBy = createdBy;
    }
    //Getters and setters omitted for brevity
}
This way, the id property serves as both Primary Key and Foreign Key. You'll notice that the @Id column no longer uses a @GeneratedValue annotation since the identifier is populated with the identifier of the post association.
Many-to-many
The many-to-many table relationship looks as follows:

In a relational database system, a many-to-many table relationship links two parent tables via a child table which contains two Foreign Key columns referencing the Primary Key columns of the two parent tables.
In the table diagram above, the post_id column in the post_tag table has also a Foreign Key relationship with the post table id Primary Key column:
    ALTER TABLE
        post_tag
    ADD CONSTRAINT
        fk_post_tag_post_id
    FOREIGN KEY (post_id) REFERENCES post
And, the tag_id column in the post_tag table has a Foreign Key relationship with the tag table id Primary Key column:
    ALTER TABLE
        post_tag
    ADD CONSTRAINT
        fk_post_tag_tag_id
    FOREIGN KEY (tag_id) REFERENCES tag
Using the JPA @ManyToMany mapping
This is how you can map the many-to-many table relationship with JPA and Hibernate:
    @Entity(name = "Post")
    @Table(name = "post")
    public class Post {
        @Id
        @GeneratedValue
        private Long id;
        private String title;
        @ManyToMany(cascade = { 
            CascadeType.PERSIST, 
            CascadeType.MERGE
        })
        @JoinTable(name = "post_tag",
            joinColumns = @JoinColumn(name = "post_id"),
            inverseJoinColumns = @JoinColumn(name = "tag_id")
        )
        private Set<Tag> tags = new HashSet<>();
        //Getters and setters ommitted for brevity
        public void addTag(Tag tag) {
            tags.add(tag);
            tag.getPosts().add(this);
        }
        public void removeTag(Tag tag) {
            tags.remove(tag);
            tag.getPosts().remove(this);
        }
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof Post)) return false;
            return id != null && id.equals(((Post) o).getId());
        }
        @Override
        public int hashCode() {
            return getClass().hashCode();
        }
    }
    @Entity(name = "Tag")
    @Table(name = "tag")
    public class Tag {
        @Id
        @GeneratedValue
        private Long id;
        @NaturalId
        private String name;
        @ManyToMany(mappedBy = "tags")
        private Set<Post> posts = new HashSet<>();
        //Getters and setters ommitted for brevity
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Tag tag = (Tag) o;
            return Objects.equals(name, tag.name);
        }
        @Override
        public int hashCode() {
            return Objects.hash(name);
        }
    }
- The tagsassociation in thePostentity only defines thePERSISTandMERGEcascade types. TheREMOVEentity state transition doesn't make any sense for a@ManyToManyJPA association since it could trigger a chain deletion that would ultimately wipe both sides of the association.
- The add/remove utility methods are mandatory if you use bidirectional associations so that you can make sure that both sides of the association are in sync.
- The Postentity uses the entity identifier for equality since it lacks any unique business key. You can use the entity identifier for equality as long as you make sure that it stays consistent across all entity state transitions.
- The Tagentity has a unique business key which is marked with the Hibernate-specific@NaturalIdannotation. When that's the case, the unique business key is the best candidate for equality checks.
- The mappedByattribute of thepostsassociation in theTagentity marks that, in this bidirectional relationship, thePostentity owns the association. This is needed since only one side can own a relationship, and changes are only propagated to the database from this particular side.
- The Setis to be preferred, as using aListwith@ManyToManyis less efficient.