You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

单向One To Many关联添加方法触发Proxy调用异常求助

单向OneToMany关联添加Author时的报错排查与解决

错误信息

at jdk.proxy2/jdk.proxy2.$Proxy106.save(Unknown Source) ~[na:na] at
com.example.OneToManyUniDirectional.service.concretes.AuthorManager.addAuthor(AuthorManager.java:50)
~[classes/:na] at
com.example.OneToManyUniDirectional.controller.AuthorController.addAuthors(AuthorController.java:21)
~[classes/:an]

相关代码

Author实体类

public class Author {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name="name")
    private String firstName;
    @Column(name="surname")
    private String lastName;
    @OneToMany(cascade=CascadeType.MERGE,fetch = FetchType.EAGER)
    private Set<Book> books=new HashSet<>();
    
}

Book实体类

public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String isbn;
    @Column(name="book_name")
    private String name;
}

addAuthor业务方法

@Override
public void addAuthor(CreateAuthor createAuthor){
    Author author=new Author();
    author.setFirstName(createAuthor.getFirstName());
    author.setLastName(createAuthor.getLastName());
    if(this.bookRepository.findById(createAuthor.getBook().getId()).isPresent()){
        UpdateBook updateBook=new UpdateBook();
        updateBook.setName(createAuthor.getBook().getName());
        updateBook.setIsbn(createAuthor.getBook().getIsbn());
        this.bookService.updateBook(updateBook,createAuthor.getBook().getId());
    }
    else{
        CreateBook createBook=new CreateBook();
        createBook.setName(createAuthor.getBook().getName());
        createBook.setIsbn(createAuthor.getBook().getIsbn());
        this.bookService.addBook(createBook);
        author.getBooks().add(createAuthor.getBook());
    }
    this.authorRepository.save(author);
}

CreateAuthor DTO

@Data
@NoArgsConstructor
@AllArgsConstructor
public class CreateAuthor {
    private String firstName;
    private String lastName;
    private Book book;
}

Controller代码

@PostMapping("/authors")
public void addAuthors(@RequestBody CreateAuthor createAuthor){
    this.authorService.addAuthor(createAuthor);
}

注:CreateBook和UpdateBook类不含id属性

报错原因分析

  1. 单向OneToMany关联配置缺失:@OneToMany未指定@JoinColumn,Hibernate会自动创建中间表维护关联,但此时关联的Book实体状态不符合要求,导致保存Author时关联处理失败。
  2. 游离态实体操作问题:CreateAuthor中传递的Book是从请求体反序列化的游离态对象,cascade=CascadeType.MERGE仅支持合并持久态或托管态实体,无法处理游离态,触发代理类的save方法报错。
  3. 新增Book后关联对象错误:新增Book时,调用bookService.addBook(createBook)后,直接将传入的未持久化Book对象添加到Author的集合,该对象未被Hibernate托管,保存Author时无法正确关联。

解决办法

1. 修正OneToMany关联配置

给Author的@OneToMany添加@JoinColumn,明确外键列,避免自动生成中间表,同时调整cascade类型覆盖新增场景:

@OneToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST}, fetch = FetchType.EAGER)
@JoinColumn(name = "author_id") // 指定Book表中的外键列
private Set<Book> books = new HashSet<>();

2. 重构CreateAuthor的字段类型

不要直接传递Book实体,改用CreateBook DTO,避免传递游离态实体:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class CreateAuthor {
    private String firstName;
    private String lastName;
    private CreateBook book; // 替换为CreateBook DTO
}

3. 修正addAuthor方法逻辑

确保添加到Author集合的是持久态Book对象,同时简化逻辑:

@Override
public void addAuthor(CreateAuthor createAuthor){
    Author author = new Author();
    author.setFirstName(createAuthor.getFirstName());
    author.setLastName(createAuthor.getLastName());
    
    CreateBook createBook = createAuthor.getBook();
    Book book;
    // 检查Book是否存在(需给CreateBook添加id字段支持更新场景)
    if (createBook.getId() != null && bookRepository.findById(createBook.getId()).isPresent()) {
        // 更新现有Book
        book = bookRepository.findById(createBook.getId()).get();
        book.setName(createBook.getName());
        book.setIsbn(createBook.getIsbn());
        bookRepository.save(book);
    } else {
        // 新增Book并获取持久态对象
        book = new Book();
        book.setName(createBook.getName());
        book.setIsbn(createBook.getIsbn());
        book = bookRepository.save(book);
    }
    // 将持久态Book添加到Author集合
    author.getBooks().add(book);
    authorRepository.save(author);
}

4. 调整BookService的addBook方法

确保addBook返回持久化后的Book对象:

public Book addBook(CreateBook createBook) {
    Book book = new Book();
    book.setName(createBook.getName());
    book.setIsbn(createBook.getIsbn());
    return bookRepository.save(book);
}

内容的提问来源于stack exchange,提问作者samaritan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 06:30:37