在Spring Data JPA中,使用@OneToMany和@ManyToOne来表示一对多的双向关联。例如,一端(Author)使用@OneToMany,多端(Article)使用@ManyToOne。
    在JPA规范中,一对多的双向关系由多端(如Article)来维护。就是说多端为关系的维护端,负责关系的增删改查。一端则为关系的被维护端,不能维护关系。
    一端(Author)使用@OneToMany注解的mappedBy="author"属性表明一端(Author)是关系的被维护端。多端(Article)使用@ManyToOne和@JoinColumn来注解属性author,@ManyToOne表明Article是多端,@JoinColumn设置在article表的关联字段(外键)上。
使用Spring Data JPA实现Author与Article的一对多关系映射

1)创建持久化实体类
2)创建数据访问层
3)创建业务层
4)创建控制器类
5)运行
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.onetomany</groupId>
    <artifactId>SpringBootOneToMany</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <!-- 声明项目配置依赖编码格式为 utf-8 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <fastjson.version>1.2.24</fastjson.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 添加MySQL依赖 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
            <version>8.0.13</version><!--$NO-MVN-MAN-VER$ -->
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
server.port=8089

server.servlet.context-path=/ch6_2
spring.datasource.url=jdbc:mysql://localhost:3306/springbootjpa?serverTimezone=UTC&autoReconnect=true
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.database=MYSQL
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jackson.serialization.indent-output=true 
1)创建持久化实体类

在com.ch.ch6_2.entity包中,创建名为Author和Article的持久化实体类。


@Entity
@Table(name = "author_table")
@JsonIgnoreProperties(value = { "hibernateLazyInitializer"})
public class Author implements Serializable{
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    //作者名
    private String aname;
    //文章列表,作者与文章是一对多的关系
    @OneToMany(
            mappedBy = "author",
            cascade=CascadeType.ALL,
            targetEntity = Article.class, 
            fetch=FetchType.LAZY
            )
    private List<Article> articleList;
    //省略set和get方法
}
package com.ch.ch6_2.entity;

import java.io.Serializable;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@Entity
@Table(name = "author_table")
@JsonIgnoreProperties(value = { "hibernateLazyInitializer" })
public class Author implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    // 作者名
    private String aname;
    // 文章列表,作者与文章是一对多的关系
    @OneToMany(mappedBy = "author", cascade = CascadeType.ALL, targetEntity = Article.class, fetch = FetchType.LAZY)
    private List<Article> articleList;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getAname() {
        return aname;
    }

    public void setAname(String aname) {
        this.aname = aname;
    }

    public List<Article> getArticleList() {
        return articleList;
    }

    public void setArticleList(List<Article> articleList) {
        this.articleList = articleList;
    }
}
package com.ch.ch6_2.entity;

import java.io.Serializable;

import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@Entity
@Table(name = "article_table")
@JsonIgnoreProperties(value = { "hibernateLazyInitializer" })
public class Article implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    // 标题
    @NotEmpty(message = "标题不能为空")
    @Size(min = 2, max = 50)
    @Column(nullable = false, length = 50)
    private String title;

    // 文章内容
    @Lob // 大对象,映射 为MySQL的Long文本类型
    @Basic(fetch = FetchType.LAZY)
    @NotEmpty(message = "内容不能为空")
    @Size(min = 2)
    @Column(nullable = false)
    private String content;

    // 所属作者,文章与作者是多对一的关系
    @ManyToOne(cascade = { CascadeType.MERGE, CascadeType.REFRESH }, optional = false)
    // 可选属性optional=false,表示author不能为空。删除文章,不影响用户
    @JoinColumn(name = "id_author_id") // 设置在article表中的关联字段(外键)
    @JsonIgnore
    private Author author;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public Author getAuthor() {
        return author;
    }

    public void setAuthor(Author author) {
        this.author = author;
    }
}
2)创建数据访问层

在com.ch.ch6_2.repository包中,创建名为AuthorRepository和ArticleRepository的接口。
package com.ch.ch6_2.repository;

//import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import com.ch.ch6_2.entity.Author;

public interface AuthorRepository extends JpaRepository<Author, Integer> {
    /**
     * 根据文章标题包含的内容,查询作者(关联查询) 相当于JPQL语句:select a from Author a inner join
     * a.articleList t where t.title like %?1%
     */
    public Author findByArticleList_titleContaining(String title);

    /**
     * 根据文章标题包含的内容,查询作者(关联查询)
     */
    @Query("select a from Author a  inner join  a.articleList t where t.title like %?1%")
    public Author findAuthorByArticleListtitleContaining(String title);
}
package com.ch.ch6_2.repository;

import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import com.ch.ch6_2.entity.Article;

public interface ArticleRepository extends JpaRepository<Article, Integer> {
    /**
     * 根据作者id查询文章信息(关联查询,根据author属性的id) 相当于JPQL语句:select a from Article a where
     * a.author.id = ?1
     */
    public List<Article> findByAuthor_id(Integer id);

    /**
     * 根据作者名查询文章信息(关联查询,根据author属性的aname) 相当于JPQL语句:select a from Article a where
     * a.author.aname = ?1
     */
    public List<Article> findByAuthor_aname(String aname);
}
3)创建业务层

在com.ch.ch6_2.service包中,创建名为AuthorAndArticleService的接口和接口实现类AuthorAndArticleServiceImpl。
package com.ch.ch6_2.service;

import java.util.List;

import com.ch.ch6_2.entity.Article;
import com.ch.ch6_2.entity.Author;

public interface AuthorAndArticleService {
    public void saveAll();

    public List<Article> findByAuthor_id(Integer id);

    public List<Article> findByAuthor_aname(String aname);

    public Author findByArticleList_titleContaining(String title);

    public Author findAuthorByArticleListtitleContaining(String title);
}
package com.ch.ch6_2.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ch.ch6_2.entity.Article;
import com.ch.ch6_2.entity.Author;
import com.ch.ch6_2.repository.ArticleRepository;
import com.ch.ch6_2.repository.AuthorRepository;

@Service
public class AuthorAndArticleServiceImpl implements AuthorAndArticleService {
    @Autowired
    private AuthorRepository authorRepository;
    @Autowired
    private ArticleRepository articleRepository;

    @Override
    public void saveAll() {
        // 保存作者(先保存一的一端)
        Author a1 = new Author();
        a1.setAname("陈恒1");
        Author a2 = new Author();
        a2.setAname("陈恒2");
        ArrayList<Author> allAuthor = new ArrayList<Author>();
        allAuthor.add(a1);
        allAuthor.add(a2);
        authorRepository.saveAll(allAuthor);
        // 保存文章
        Article at1 = new Article();
        at1.setTitle("JPA的一对多111");
        at1.setContent("其实一对多映射关系很常见111。");
        // 设置关系
        at1.setAuthor(a1);
        Article at2 = new Article();
        at2.setTitle("JPA的一对多222");
        at2.setContent("其实一对多映射关系很常见222。");
        // 设置关系
        at2.setAuthor(a1);// 文章2与文章1作者相同
        Article at3 = new Article();
        at3.setTitle("JPA的一对多333");
        at3.setContent("其实一对多映射关系很常见333。");
        // 设置关系
        at3.setAuthor(a2);
        Article at4 = new Article();
        at4.setTitle("JPA的一对多444");
        at4.setContent("其实一对多映射关系很常见444。");
        // 设置关系
        at4.setAuthor(a2);// 文章3与文章4作者相同
        ArrayList<Article> allAt = new ArrayList<Article>();
        allAt.add(at1);
        allAt.add(at2);
        allAt.add(at3);
        allAt.add(at4);
        articleRepository.saveAll(allAt);
    }

    @Override
    public List<Article> findByAuthor_id(Integer id) {
        return articleRepository.findByAuthor_id(id);
    }

    @Override
    public List<Article> findByAuthor_aname(String aname) {
        return articleRepository.findByAuthor_aname(aname);
    }

    @Override
    public Author findByArticleList_titleContaining(String title) {
        return authorRepository.findByArticleList_titleContaining(title);
    }

    @Override
    public Author findAuthorByArticleListtitleContaining(String title) {
        return authorRepository.findAuthorByArticleListtitleContaining(title);
    }
}
4)创建控制器类

在com.ch.ch6_2.controller包中,创建名为TestOneToManyController的控制器类。
package com.ch.ch6_2.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.ch.ch6_2.entity.Article;
import com.ch.ch6_2.entity.Author;
import com.ch.ch6_2.service.AuthorAndArticleService;

@RestController
public class TestOneToManyController {
    @Autowired
    private AuthorAndArticleService authorAndArticleService;

    @RequestMapping("/saveOneToMany")
    public String save() {
        authorAndArticleService.saveAll();
        return "作者和文章保存成功!";
    }

    @RequestMapping("/findArticleByAuthor_id")
    public List<Article> findByAuthor_id(Integer id) {
        return authorAndArticleService.findByAuthor_id(id);
    }

    @RequestMapping("/findArticleByAuthor_aname")
    public List<Article> findByAuthor_aname(String aname) {
        return authorAndArticleService.findByAuthor_aname(aname);
    }

    @RequestMapping("/findByArticleList_titleContaining")
    public Author findByArticleList_titleContaining(String title) {
        return authorAndArticleService.findByArticleList_titleContaining(title);
    }

    @RequestMapping("/findAuthorByArticleListtitleContaining")
    public Author findAuthorByArticleListtitleContaining(String title) {
        return authorAndArticleService.findAuthorByArticleListtitleContaining(title);
    }
}
首先,运行Ch62Application主类。然后,访问“http://localhost:8089/ch6_2/saveOneToMany/”。
package com.ch.ch6_2;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Ch62Application {
    public static void main(String[] args) {
        SpringApplication.run(Ch62Application.class, args);
    }
}