Java spring数据jpa多对多findByID

Java spring数据jpa多对多findByID,java,spring-boot,spring-data-jpa,many-to-many,Java,Spring Boot,Spring Data Jpa,Many To Many,我有书和作者之间的多对多关系,我有三个表:作者、书和作者书 @Entity() @Table(name = "author") public class Author implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; @ManyToMany(casca

我有书和作者之间的多对多关系,我有三个表:作者、书和作者书

@Entity()
@Table(name = "author")
public class Author implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinTable(
            name = "author_book",
            joinColumns = @JoinColumn(name = "author_id"),
            inverseJoinColumns = @JoinColumn(name = "book_id")
    )
    private List<Book> authorBooks = new ArrayList<Book>();

    public Author() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Book> getAuthorBooks() {
        return authorBooks;
    }

    public void setAuthorBooks(List<Book> authorBooks) {
        this.authorBooks = authorBooks;
    }

    @Override
    public String toString() {
        return "Author{" + "name=" + name + ", authorBooks=" + authorBooks + '}';
    }

}


@Entity()
@Table(name = "book")
public class Book implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;

    @ManyToMany(mappedBy = "authorBooks", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<Author> bookAuthors = new ArrayList<Author>();

    public Book() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Author> getBookAuthors() {
        return bookAuthors;
    }

    public void setBookAuthors(List<Author> bookAuthors) {
        this.bookAuthors = bookAuthors;
    }

    @Override
    public String toString() {
        return "Book{" + "name=" + name + ", bookAuthors=" + bookAuthors + '}';
    }

}
@Entity()
@表(name=“author”)
公共类Author实现了可序列化{
@身份证
@GeneratedValue(策略=GenerationType.AUTO)
私人长id;
私有字符串名称;
@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
@可接合(
name=“author\u book”,
joinColumns=@JoinColumn(name=“author\u id”),
inverseJoinColumns=@JoinColumn(name=“book\u id”)
)
私有列表authorBooks=new ArrayList();
公共作者(){
}
公共字符串getName(){
返回名称;
}
公共void集合名(字符串名){
this.name=名称;
}
公共列表getAuthorBooks(){
返回authorBooks;
}
public void setAuthorBooks(列出authorBooks){
this.authorBooks=authorBooks;
}
@凌驾
公共字符串toString(){
返回“Author{“+”name=“+name+”,authorBooks=“+authorBooks+'}”;
}
}
@实体()
@表(name=“book”)
公共类图书实现了可序列化{
@身份证
@GeneratedValue(策略=GenerationType.AUTO)
私人长id;
私有字符串名称;
@ManyToMany(mappedBy=“authorBooks”,cascade=CascadeType.ALL,fetch=FetchType.LAZY)
private List bookAuthors=new ArrayList();
公共书籍(){
}
公共字符串getName(){
返回名称;
}
公共void集合名(字符串名){
this.name=名称;
}
公共列表getBookAuthors(){
返回图书作者;
}
公共书籍作者(列出书籍作者){
this.bookAuthors=bookAuthors;
}
@凌驾
公共字符串toString(){
返回“Book{”+“name=“+name+”,bookAuthors=“+bookAuthors+”}”;
}
}
我可以毫无问题地将数据添加到db中,但是当我想通过id获取作者或书籍时

Optional<Author> optionalAuthor = authorReposi.findById(1L);
System.out.println("Author: " + optionalAuthor.get().toString());
可选选项author=authorReposi.findById(1L);
System.out.println(“作者:+optionalAuthor.get().toString());
我收到一个错误:懒散初始化失败…

我想使用FetchType.LAZY并获取author或book的实例

谢谢您的时间。

所以,请阅读精美手册:

您的问题很简单,您的
toString()
方法是递归的<代码>作者表示打印
书籍
书籍
表示打印
作者
。专业提示:成功在于细节

对于
load
fetch
,您需要使用
JPA
中的
EntityGraph
来指定连接的属性。因此:

@Entity()
@Table(name = "author")
@NamedEntityGraph(name = "Book.detail", attributeNodes = @NamedAttributeNode("books"))
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Author {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;

    @ManyToMany
    private List<Book> books;
}
最后,我避免像瘟疫一样使用
Cascade
注释。它们是复杂的注释。另外,默认情况下,
manytomy
FetchType.LAZY
。重要的注释是
mappedBy
注释。这将告诉您哪个实体拥有关系。拥有实体是负责维持关系的实体。双向注释的另一面实际上只用于查询。不需要在实体中创建新的
ArrayList
,因为它们在查询过程中会被丢弃。当需要持久化具有关系的新
作者
实体时,只需创建一个列表,否则使用查询返回的列表

private Author save() {
    Book b = bookRepository.save(Book.builder().name("b1").build());
    return authorRepository.save(Author.builder().name("a1").books(Collections.singletonList(b)).build());
}

这可能有助于您始终不一致地使用
author
auhtor
。正确的拼写是
author
。我建议重命名所有内容以与此对齐,然后看看会发生什么。@Jason我修复了作者的拼写,仍然有相同的问题。谢谢你们。谢谢你们的解释,它正在工作。我将使用EntityGraph。是否可以执行此调用:author.getBooks().get(0).getAuthors()我必须添加cascade=CascadeType.ALL才能将新的author添加到db中。1)我认为这是可能的,但您必须尝试。查看实体图的子图。2) 我将一个新作者保存到数据库中,如上所示。也许你将CASCADE添加到Books实体中是为了从那里拯救作者,但我个人不建议这样做。我认为最好保持JPA注释的基础性,并根据需要创建一个处理各种不同情况的服务层。
public interface AuthorRepository extends JpaRepository<Author, Long>{
    @EntityGraph(value = "Book.detail", type = EntityGraphType.LOAD)
    Author getById(Long id);
}
public interface BookRepository extends JpaRepository<Book, Long>{

}
private void read(Long id) {
    Author a = authorRepository.getById(id);
    System.out.println("Author: " + a.getName());
    for( Book b: a.getBooks()) {
        System.out.println("\tBook: " + b.getName());
    }
}
private Author save() {
    Book b = bookRepository.save(Book.builder().name("b1").build());
    return authorRepository.save(Author.builder().name("a1").books(Collections.singletonList(b)).build());
}