在本文中,您将学习如何使用 JPA 和 Hibernate 在应用程序中的对象级别映射多对多数据库关系。
考虑以下表格,其中 posts
和 tags
显示彼此之间的多对多关系 -
多对多关系是使用名为 post_tags
的第三个表实现的,该表包含帖子的详细信息及其相关标签。
现在让我们从头开始创建一个项目,并学习如何使用 JPA 和 Hibernate 实现这种多对多关系。
您可以通过在终端中键入以下命令来使用 Spring Boot CLI 创建项目 -
spring init -n=jpa-many-to-many-demo -d=web,jpa,mysql --package-name=com.example.jpa jpa-many-to-many-demo
如果您没有安装 Spring Boot CLI,您可以使用 Spring Initializr 网络工具按照以下说明引导项目 -
以下是项目的目录结构供大家参考——
此时,您的引导项目不会有 model
和 repository
包以及这些包中的所有类。我们很快就会创建它们。
我们需要配置 MySQL 数据库 URL、用户名和密码,以便 Spring 可以在启动时与数据库建立连接。
打开 src/main/resources/application.properties
并向其添加以下属性 -
# DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url=jdbc:mysql://localhost:3306/jpa_many_to_many_demo?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false
spring.datasource.username=root
spring.datasource.password=root
# Hibernate
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE
请务必根据您的 MySQL 安装更改 spring.datasource.username
和 spring.datasource.password
属性。此外,创建一个名为 jpa_many_to_many_demo
的数据库。
spring.jpa.hibernate.ddl-auto = update
属性确保应用程序中的数据库表和域模型同步。每当您更改域模型时,hibernate 将在您重新启动应用程序时自动更新数据库中的映射表。
我还指定了 hibernate 的日志级别,以便我们可以调试 hibernate 执行的 SQL 查询。
让我们定义将映射到我们之前看到的表的域模型。首先,在 com.example.jpa
中创建一个名为 model
的包,然后在 model
包中添加以下类 -
1.后模型
package com.example.jpa.model;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "posts")
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
@Size(max = 100)
@Column(unique = true)
private String title;
@NotNull
@Size(max = 250)
private String description;
@NotNull
@Lob
private String content;
@NotNull
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "posted_at")
private Date postedAt = new Date();
@NotNull
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "last_updated_at")
private Date lastUpdatedAt = new Date();
@ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
@JoinTable(name = "post_tags",
joinColumns = { @JoinColumn(name = "post_id") },
inverseJoinColumns = { @JoinColumn(name = "tag_id") })
private Set<Tag> tags = new HashSet<>();
public Post() {
}
public Post(String title, String description, String content) {
this.title = title;
this.description = description;
this.content = content;
}
// Getters and Setters (Omitted for brevity)
}
2.标签型号
package com.example.jpa.model;
import org.hibernate.annotations.NaturalId;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "tags")
public class Tag {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
@Size(max = 100)
@NaturalId
private String name;
@ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
},
mappedBy = "tags")
private Set<Post> posts = new HashSet<>();
public Tag() {
}
public Tag(String name) {
this.name = name;
}
// Getters and Setters (Omitted for brevity)
}
我们使用 @ManyToMany
注释在两个实体之间创建多对多关系。在双向关联中,@ManyToMany
注释用于两个实体,但只有一个实体可以是关系的所有者。
指定 @JoinTable
的实体是关系的拥有方,指定 mappedBy
属性的实体是反面。
在上面的例子中,Post
实体是关系的所有者,而 Tag
实体是相反的一方。
让我们定义 repositories
来访问数据库中的 Post
和 Tag
数据。
首先,在 com.example.jpa
包中创建一个名为 repository
的新包,然后在 repository
包中创建以下存储库 -
1. PostRepository
package com.example.jpa.repository;
import com.example.jpa.model.Post;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface PostRepository extends JpaRepository<Post, Long> {
}
2.标签库
package com.example.jpa.repository;
import com.example.jpa.model.Tag;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface TagRepository extends JpaRepository<Tag, Long> {
}
是时候编写一些代码来测试我们的多对多关联设置了。打开主类 JpaManyToManyDemoApplication.java
并将其替换为以下代码 -
package com.example.jpa;
import com.example.jpa.model.Post;
import com.example.jpa.model.Tag;
import com.example.jpa.repository.PostRepository;
import com.example.jpa.repository.TagRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class JpaManyToManyDemoApplication implements CommandLineRunner {
@Autowired
private TagRepository tagRepository;
@Autowired
private PostRepository postRepository;
public static void main(String[] args) {
SpringApplication.run(JpaManyToManyDemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
// Cleanup the tables
postRepository.deleteAllInBatch();
tagRepository.deleteAllInBatch();
// =======================================
// Create a Post
Post post = new Post("Hibernate Many to Many Example with Spring Boot",
"Learn how to map a many to many relationship using hibernate",
"Entire Post content with Sample code");
// Create two tags
Tag tag1 = new Tag("Spring Boot");
Tag tag2 = new Tag("Hibernate");
// Add tag references in the post
post.getTags().add(tag1);
post.getTags().add(tag2);
// Add post reference in the tags
tag1.getPosts().add(post);
tag2.getPosts().add(post);
postRepository.save(post);
// =======================================
}
}
上述类中的 run()
方法在应用程序启动时被调用。在 run()
方法中,我们首先清理表格,然后创建一个 Post,两个标签,然后在帖子中添加标签。最后,我们使用 PostRepository::save()
方法保存帖子引用,该方法也保存标签。
您可以通过在终端中键入以下命令来运行该应用程序 -
mvn spring-boot:run
应用程序启动后,检查控制台是否有 hibernate 特定的日志,以查看 hibernate 为我们在 run()
方法中执行的操作执行了哪些 SQL 语句 -
org.hibernate.SQL : delete from post_tags where (post_id) in (select id from posts)
org.hibernate.SQL : delete from posts
org.hibernate.SQL : delete from post_tags where (tag_id) in (select id from tags)
org.hibernate.SQL : delete from tags
org.hibernate.SQL : insert into posts (content, description, last_updated_at, posted_at, title) values (?, ?, ?, ?, ?)
org.hibernate.SQL : insert into tags (name) values (?)
org.hibernate.SQL : insert into tags (name) values (?)
org.hibernate.SQL : insert into post_tags (post_id, tag_id) values (?, ?)
org.hibernate.SQL : insert into post_tags (post_id, tag_id) values (?, ?)
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://www.callicoder.com/hibernate-spring-boot-jpa-many-to-many-mapping-example/
内容来源于网络,如有侵权,请联系作者删除!