Spring Boot双向OneToMany映射未用mappedBy,关联表无记录怎么解决?
双向OneToMany映射关联表无记录的解决方法
问题背景
基于Spring Boot框架做了个双向OneToMany映射的项目,包含Customer和Branch两个实体,一个Branch对应多个Customer。因为没加mappedBy,数据库自动生成了一张额外的关联表,但这张表里没数据,而Customer和Branch表已经有数据了,现在要让关联表生成对应的记录。
Customer.java 实体类代码
package com.shiva.enterprises.banking.repositories; import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; import org.hibernate.validator.constraints.Range; import java.time.LocalDateTime; @Entity @Table(name="BANK_CUSTOMER") @Getter @Setter public class Customer { @Column(name="FIRST_NAME", length = 50) private String firstName; @Column(name="LAST_NAME", length = 50) private String lastName; @Id @Range(min = 10000, max = 99999, message = "CIF Number must be 5-digit number.") @Column(name="CIF_NO", length = 5) private int cifNo; @Column(name="REGISTERED_DATE") @JsonFormat(pattern = "dd/MMM/yyyy") private LocalDateTime registeredDate; @Column(name="ACCOUNT_BALANCE") private long balance; @Column(name="STATUS") private String status; @Range(min = 10000000, max = 99999999, message = "Account number must be 8-digit number.") @Column(name="ACCOUNT_NO", length = 8) private long accNo; //Adding address @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name="ADDRESS_ID") private Address address; //Adding Branch @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinColumn(name="BRANCH_CODE") private Branch branch; }
Branch.java 实体类代码
package com.shiva.enterprises.banking.repositories; import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; import org.hibernate.validator.constraints.Range; import java.util.ArrayList; @Getter @Setter @Entity @Table(name="BANK_BRANCH") public class Branch { @Id @Column(name="BRANCH_NO") @Range(min=10000, max=99999, message = "Please enter valid branch number.") private int branchNo; @Column(name="BRANCH_NAME") private String branchName; @Column(name="BRANCH_ADDRESS") private String branchAddress; @OneToMany(fetch = FetchType.LAZY) private ArrayList<Customer> customers; }
解决步骤
1. 修正双向映射配置
现在的问题是Branch类的@OneToMany没加mappedBy,JPA会把它当成独立的单向关联,所以自动生成了中间表。但你已经在Customer里用@ManyToOne指定了外键BRANCH_CODE,所以要把Branch的映射改成双向关联的正确写法:
修改Branch类的@OneToMany注解:
@OneToMany(fetch = FetchType.LAZY, mappedBy = "branch", cascade = CascadeType.ALL) private List<Customer> customers = new ArrayList<>();
mappedBy = "branch":明确这个关联由Customer类里的branch属性维护(也就是外键所在的一方),这样JPA就不会再生成多余的关联表。- 把
ArrayList换成List接口更符合JPA规范,避免不必要的类型限制。 cascade = CascadeType.ALL是可选配置,根据你的业务需求调整,比如删除分支时要不要连带删除客户。
2. 手动维护双向关联的一致性
双向关联里,必须同时设置双方的引用,否则关联关系不会被正确持久化。比如创建新数据时:
// 创建分支 Branch branch = new Branch(); branch.setBranchNo(10001); branch.setBranchName("Central Branch"); branch.setBranchAddress("Main Street"); // 创建客户 Customer customer = new Customer(); customer.setCifNo(12345); customer.setFirstName("John"); customer.setLastName("Doe"); // 填充客户其他属性... // 同时设置双方关联 customer.setBranch(branch); branch.getCustomers().add(customer); // 保存数据(因为配置了cascade,只保存分支就能级联保存客户) branchRepository.save(branch);
3. 处理已存在的数据关联
如果数据库里已经有Customer和Branch数据,但关联表没记录,需要批量更新关联关系:
// 查询所有分支和客户 List<Branch> branches = branchRepository.findAll(); List<Customer> customers = customerRepository.findAll(); // 根据业务规则匹配客户和分支(比如用分支编号匹配客户的BRANCH_CODE) for (Customer customer : customers) { Branch matchedBranch = branches.stream() .filter(b -> b.getBranchNo() == customer.getBranch().getBranchNo()) .findFirst() .orElse(null); if (matchedBranch != null) { customer.setBranch(matchedBranch); matchedBranch.getCustomers().add(customer); } } // 批量保存更新后的关联关系 branchRepository.saveAll(branches); customerRepository.saveAll(customers);
4. 清理多余的关联表
修正映射后,之前自动生成的关联表(一般叫BANK_BRANCH_CUSTOMERS这类名字)就没用了,可以手动删除,或者把JPA的spring.jpa.hibernate.ddl-auto配置改成update,让框架自动清理无效的表。
内容的提问来源于stack exchange,提问作者Shivam Tiwari
相关产品推荐
相关产品推荐

