Spring Data JPA04 -多表

级联操作

指操作一个对象同时操作它的关联对象

在操作主体的注解上配置cascade

  1. CascadeType.MERGE 级联更新
  2. CascadeType.REFRESH 级联刷新:
  3. CascadeType.REMOVE 级联删除:
  4. CascadeType.PERSIST 级联保存:
  5. CascadeType.ALL 包含所有

@OneToMany(mappedBy="customer",cascade=CascadeType.ALL)

一对多 多对一

@OneToMany

  1. targetEntityClass:指定多的多方的类的字节码
  2. mappedBy:指定从表实体类中引用主表对象的名称。
  3. cascade:指定要使用的级联操作
  4. fetch:指定是否采用延迟加载
  5. orphanRemoval:是否使用孤儿删除

@ManyToOne

  1. targetEntityClass:指定一的一方实体类字节码
  2. cascade:指定要使用的级联操作
  3. fetch:指定是否采用延迟加载
  4. optional:关联是否可选。如果设置为false,则必须始终存在非空关系。

@JoinColumn

用于定义主键字段和外键字段的对应关系

  1. name:指定外键字段的名称
  2. referencedColumnName:指定引用主表的主键字段名称
  3. unique:是否唯一。默认值不唯一
  4. nullable:是否允许为空。默认值允许
  5. insertable:是否允许插入。默认值允许。
  6. updatable:是否允许更新。默认值允
  7. columnDefinition:列的定义信息。
@Getter
@Setter
@Entity
@Table(name="cst_customer")
public class Customer  implements Serializable {

  @Id
  @GeneratedValue(strategy= GenerationType.IDENTITY)
  @Column(name="cust_id")
  private Long custId;

  @Column(name="cust_name",columnDefinition = "varchar(32) NOT NULL")
  private String custName;

  @Column(name="cust_source")
  private String custSource;

  @Column(name="cust_industry")
  private String custIndustry;

  @Column(name="cust_level")
  private String custLevel;

  @Column(name="cust_address")
  private String custAddress;

  @Column(name="cust_phone")
  private String custPhone;

  @OneToMany(mappedBy = "customer",cascade = CascadeType.ALL)
  private Set<LinkMan> linkMans = new HashSet<>();

}
@Getter
@Setter
@Entity
@Table(name="cst_linkman")
@EqualsAndHashCode
public class LinkMan {
  @Id
  @GeneratedValue(strategy= GenerationType.IDENTITY)
  @Column(name="lkm_id")
  private Long lkmId;
  @Column(name="lkm_name")
  private String lkmName;
  @Column(name="lkm_gender")
  private String lkmGender;
  @Column(name="lkm_phone")
  private String lkmPhone;
  @Column(name="lkm_mobile")
  private String lkmMobile;
  @Column(name="lkm_email")
  private String lkmEmail;
  @Column(name="lkm_position")
  private String lkmPosition;
  @Column(name="lkm_memo")
  private String lkmMemo;


  @ManyToOne(targetEntity = Customer.class,fetch = FetchType.LAZY)
  @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
  private Customer customer;
}

当我们建立了双向的关联关系之后,先保存主表,再保存从表时:

会产生2条insert和1条update.

而实际开发中我们只需要2条insert。

通过保存的案例,我们可以发现在设置了双向关系之后,会发送两条insert语句,一条多余的update语句,那我们的解决是思路很简单,就是一的一方放弃维护权

//    @OneToMany(targetEntity=LinkMan.class)
//    @JoinColumn(name="lkm_cust_id",referencedColumnName="cust_id")
@OneToMany(mappedBy="customer")
private Set<LinkMan> linkmans = new HashSet<LinkMan>(0);
Customer c = new Customer();
c.setCustName("TBD云集中心");

LinkMan l = new LinkMan();
l.setLkmName("TBD联系人");
l.setLkmMemo("还行吧");

LinkMan l2 = new LinkMan();
l2.setLkmName("TBD联系人1");

c.getLinkMans().add(l);
l.setCustomer(c);
c.getLinkMans().add(l2);
l2.setCustomer(c);
customerDao.save(c);
linkManDao.save(l);
linkManDao.save(l2);

删除

  1. 删除从表数据:可以随时任意删除
  2. 删除主表数据
  3. 在默认情况下,它会把外键字段置为null,然后删除主表数据。如果在数据库的表 结构上,外键字段有非空约束,默认情况就会报错了。
  4. 如果配置了放弃维护关联关系的权利,则不能删除(与外键字段是否允许为null, 没有关系)因为在删除时,它根本不会去更新从表的外键字段了。
  5. 如果还想删除,使用级联删除引用
@OneToMany(mappedBy = "customer",cascade = CascadeType.ALL)
private Set<LinkMan> linkMans = new HashSet<>();

@Test
public  void  one2ManyDelete(){
    customerDao.deleteById(9L);
}

 多对多

@ManyToMany

cascade:配置级联操作。

fetch:配置是否采用延迟加载。

targetEntity:配置目标的实体类。映射多对多的时候不用写。

@JoinTable

针对中间表的配置

nam:配置中间表的名称

joinColumns:中间表的外键字段关联当前实体类所对应表的主键字段

inverseJoinColumn:中间表的外键字段关联对方表的主键字段

@JoinColumn

用于定义主键字段和外键字段的对应关系

  1. name:指定外键字段的名称
  2. referencedColumnName:指定引用主表的主键字段名称
  3. unique:是否唯一。默认值不唯一
  4. nullable:是否允许为空。默认值允许
  5. insertable:是否允许插入。默认值允许。
  6. updatable:是否允许更新。默认值允
  7. columnDefinition:列的定义信息。
@Entity
@Table(name="sys_role")
@Setter
@Getter
public class SysRole {
  @Id
  @GeneratedValue(strategy= GenerationType.IDENTITY)
  @Column(name="role_id")
  private Long roleId;
  @Column(name="role_name")
  private String roleName;
  @Column(name="role_memo")
  private String roleMemo;


  @ManyToMany
  @JoinTable(name="sys_user_role",
             joinColumns={@JoinColumn(name="role_id",referencedColumnName="role_id")},
             inverseJoinColumns={@JoinColumn(name="user_id",referencedColumnName="user_id")}
            )
  private Set<SysUser> users = new HashSet<SysUser>(0);
}
@Entity
@Table(name="sys_user")
@Setter
@Getter
public class SysUser {
    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    @Column(name="user_id")
    private Long userId;
    @Column(name="user_code")
    private String userCode;
    @Column(name="user_name")
    private String userName;
    @Column(name="user_password")
    private String userPassword;
    @Column(name="user_state")
    private String userState;


    @ManyToMany(mappedBy="users")
    private Set<SysRole> roles = new HashSet<SysRole>(0);
}

在多对多(保存)中,如果双向都设置关系,意味着双方都维护中间表,都会往中间表插入数据,中间表的2个字段又作为联合主键,所以报错,主键重复,解决保存失败的问题:只需要在任意一方放弃对中间表的维护权即可,推荐在被动的一方放弃,配置如下:

//放弃对中间表的维护权,解决保存中主键冲突的问题

@ManyToMany(mappedBy="roles")

private Set<SysUser> users = new HashSet<SysUser>(0);

  • 14
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值