找回密码
 立即注册
首页 业界区 安全 springboot~hibernate实现外键表加载

springboot~hibernate实现外键表加载

呵烘稿 2025-9-25 19:57:25

  • https://www.baeldung.com/jpa-join-column
  • https://docs.oracle.com/javaee/6/api/javax/persistence/JoinColumn.html
  • https://stackoverflow.com/questions/37542208/what-is-joincolumn-and-how-it-is-used-in-hibernate
在 JPA 中,通过外键自动获取关联对象的值通常使用关系映射注解(如 @ManyToOne)来实现。以下是针对 am_application 表的外键关联实现:
1. 首先创建被关联的实体 AmSubscriber
  1. import jakarta.persistence.*;
  2. import lombok.Getter;
  3. import lombok.Setter;
  4. import java.time.LocalDateTime;
  5. @Getter
  6. @Setter
  7. @Entity
  8. @Table(name = "am_subscriber")
  9. public class AmSubscriber {
  10.    
  11.     @Id
  12.     @GeneratedValue(strategy = GenerationType.IDENTITY)
  13.     @Column(name = "SUBSCRIBER_ID")
  14.     private Integer subscriberId;
  15.    
  16.     @Column(name = "USER_ID", length = 64)
  17.     private String userId;
  18.    
  19.     @Column(name = "TENANT_ID")
  20.     private Integer tenantId;
  21.    
  22.     @Column(name = "EMAIL_ADDRESS", length = 256)
  23.     private String emailAddress;
  24.    
  25.     @Column(name = "DATE_SUBSCRIBED")
  26.     private LocalDateTime dateSubscribed;
  27.    
  28.     // 其他字段...
  29. }
复制代码
2. 在 AmApplication 中添加关联关系
  1. import jakarta.persistence.*;
  2. import lombok.Getter;
  3. import lombok.Setter;
  4. import org.hibernate.annotations.CreationTimestamp;
  5. import org.hibernate.annotations.UpdateTimestamp;
  6. import java.time.LocalDateTime;
  7. @Getter
  8. @Setter
  9. @Entity
  10. @Table(name = "am_application",
  11.        uniqueConstraints = {
  12.            @UniqueConstraint(name = "uk_app_name_subscriber_org", columnNames = {"name", "subscriber", "organization"}),
  13.            @UniqueConstraint(name = "uk_app_uuid", columnNames = "uuid")
  14.        },
  15.        indexes = {
  16.            @Index(name = "idx_subscriber_id", columnList = "subscriber_id"),
  17.            @Index(name = "idx_aa_at_cb", columnList = "applicationTier, createdBy")
  18.        })
  19. public class AmApplication {
  20.     @Id
  21.     @GeneratedValue(strategy = GenerationType.IDENTITY)
  22.     @Column(name = "APPLICATION_ID")
  23.     private Integer applicationId;
  24.     @Column(name = "NAME", length = 100)
  25.     private String name;
  26.     // 关键:使用 @ManyToOne 建立外键关联
  27.     @ManyToOne(fetch = FetchType.LAZY) // 推荐使用懒加载
  28.     @JoinColumn(name = "SUBSCRIBER_ID", referencedColumnName = "SUBSCRIBER_ID")
  29.     private AmSubscriber subscriber;
  30.     // 其他字段保持不变...
  31.     @Column(name = "APPLICATION_TIER", length = 50, columnDefinition = "varchar(50) default 'Unlimited'")
  32.     private String applicationTier = "Unlimited";
  33.    
  34.     // ... (其他字段)
  35. }
复制代码
关键注解说明:


  • @ManyToOne

    • 表示多对一关系(多个应用对应一个订阅者)
    • fetch = FetchType.LAZY:推荐使用懒加载,只在需要时加载关联对象

  • @JoinColumn

    • name = "SUBSCRIBER_ID":指定当前表中的外键列名
    • referencedColumnName = "SUBSCRIBER_ID":指定目标表的主键列名

使用示例:

保存新应用(自动关联订阅者)
  1. // 先获取订阅者
  2. AmSubscriber subscriber = subscriberRepository.findById(123).orElseThrow();
  3. // 创建新应用并关联订阅者
  4. AmApplication app = new AmApplication();
  5. app.setName("PaymentApp");
  6. app.setSubscriber(subscriber); // 设置关联对象
  7. app.setOrganization("finance");
  8. // 保存时会自动处理外键关系
  9. applicationRepository.save(app);
复制代码
查询应用并获取关联对象
  1. // 查询应用
  2. AmApplication app = applicationRepository.findById(456).orElseThrow();
  3. // 获取关联的订阅者信息(懒加载,首次访问时查询)
  4. System.out.println("订阅者ID: " + app.getSubscriber().getSubscriberId());
  5. System.out.println("订阅者邮箱: " + app.getSubscriber().getEmailAddress());
复制代码
JPQL 查询(自动关联)
  1. @Query("SELECT a FROM AmApplication a " +
  2.        "JOIN FETCH a.subscriber s " +  // 使用JOIN FETCH避免N+1查询
  3.        "WHERE a.organization = :org")
  4. List findByOrgWithSubscriber(@Param("org") String organization);
复制代码
自定义查询方法
  1. public interface AmApplicationRepository extends JpaRepository {
  2.    
  3.     // 通过订阅者邮箱查找应用
  4.     List findBySubscriberEmailAddress(String email);
  5.    
  6.     // 通过订阅者ID查找应用
  7.     List findBySubscriberSubscriberId(Integer subscriberId);
  8. }
复制代码
处理双向关系(可选)

如果需要在订阅者端反向访问应用列表,可以添加双向映射:
  1. // 在 AmSubscriber 类中添加
  2. @OneToMany(mappedBy = "subscriber", cascade = CascadeType.ALL)
  3. private List applications = new ArrayList<>();
  4. // 在 AmApplication 中保持关联时同步更新
  5. public void setSubscriber(AmSubscriber subscriber) {
  6.     this.subscriber = subscriber;
  7.     if (subscriber != null && !subscriber.getApplications().contains(this)) {
  8.         subscriber.getApplications().add(this);
  9.     }
  10. }
复制代码
保留两个外键字段


  • 保留subscriber_id字段
  • 保留subscriber对象字段
  • insertable = false, updatable = false属性是关键
  1. public class AmApplication {
  2.     @Id
  3.     @GeneratedValue(strategy = GenerationType.IDENTITY)
  4.     @Column(name = "APPLICATION_ID")
  5.     private Integer applicationId;
  6.     @Column(name = "NAME", length = 100)
  7.     private String name;
  8.     // 关键:使用 @ManyToOne 建立外键关联
  9.     @ManyToOne(fetch = FetchType.LAZY) // 推荐使用懒加载
  10.     @JoinColumn(name = "当前表字段SUBSCRIBER_ID", referencedColumnName = "父表字段SUBSCRIBER_ID", insertable = false, updatable = false)
  11.     private AmSubscriber subscriber;
  12.    
  13.     Column(name="SUBSCRIBER_ID")
  14.     private String SUBSCRIBER_ID;
复制代码
注意事项:


  • 避免循环引用

    • 使用 @JsonIgnore 防止 JSON 序列化无限循环
    1. @OneToMany(mappedBy = "subscriber")
    2. @JsonIgnore
    3. private List applications;
    复制代码
  • N+1 查询问题

    • 使用 JOIN FETCH 或实体图解决
    1. @EntityGraph(attributePaths = "subscriber")
    2. List findByOrganization(String org);
    复制代码
  • 更新操作

    • 更新关联对象时,JPA 会自动同步外键值
    1. // 更改应用的订阅者
    2. AmSubscriber newSub = subscriberRepository.findById(789).orElseThrow();
    3. app.setSubscriber(newSub);
    4. applicationRepository.save(app); // 自动更新外键
    复制代码
  • 删除策略

    • 默认 @ManyToOne 使用 FetchType.EAGER
    • 推荐显式设置 fetch = FetchType.LAZY
    • 删除订阅者时需先处理关联应用(或使用级联删除)

这样配置后,JPA 会自动处理外键关系,在访问 AmApplication 的 subscriber 属性时,会通过外键 SUBSCRIBER_ID 自动加载关联的 AmSubscriber 对象。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册