2020-07-10 回顾SpringdataJPA之实体关联关系

8 篇文章 0 订阅

首先先提出三个注解

@Transient

我们知道domain层中的只要你在类上写了@Entity注解,就会给你映射到数据库中,类的字段对应数据库的列,但是我们有时候会在domain层中写一些方法这时候这个注解就可以帮助我们,在方法上面写这个注解,便可以不让他映射到数据库中

@Temporal

这个注解是针对Date类型的,只要你domain层的字段是Date类型,它默认映射到数据库中是datetime类型,如果添加一个值,都是精确到秒的,但是有时候我们不希望精确到秒,比如生日这些

那么我们如何精确地指定date类型映射到表中是什么类型呢?

我想要映射到数据库是精确到秒的时间类型,我就在字段上面写上注解
@Temporal(TemporalType.TIMESTAMP)
如果我想要这个Date字段映射到数据库中是精确到日,比如生日
@Temporal(TemporalType.DATE)

在Entity中,主键生成策略

@GeneratedValue(strategy = GenerationType.IDENTITY)
这种事mysql数据库中的主键自增,不适用于oracle
@GeneratedValue(strategy = GenerationType.AUTO)
这种就是他会自动地根据你使用的数据库去选择使用哪种主键生成策略,暂时先记着这两种

关联关系之单向多对一

举例:一个客户可以有多个订单,一个订单只属于一个客户
设计Customer

@Data
@Entity
@Table(name = "t_customer")
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;
    @Column
    private String lastName;
    @Column
    private String email;
    @Column
    private Integer age;

}				----------------是多个订单对应一个客户,并且是单向的

设计Order

@Data
@Entity
@Table(name = "t_order")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;
    @Column
    private String orderName;
    //使用@ManyToOne来映射多对一的关联关系,使用@JoinColumn来映射外键,默认是使用左外链接的发送查询
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "customer_id")
    private Customer customer;
}

当做新增操作时,各插入一条,先保存客户Customer,再保存订单Order,总共发送2条SQL语句;如果先保存订单再保存客户,也是会成功的,总共会发送3条。为什么呢?

第一种:因为你先保存的客户嘛,当你保存订单时,他会去维护外键,发现外键已经有值了,他就发送一条sql用于保存订单,一条客户一条订单,总共2条
第二种:因为你先保存订单,他先给你外键设置为空,然后去保存客户去了,客户保存完了之后,多方始终都要去维护外键,发现外键为空,又发送一条sql语句去修改外键值

当做删除时,不能直接删除1的一段,因为有外键关联

关联关系之单向一对多

设计Customer

@Data
@Entity
@Table(name = "t_customer")
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;
    @Column
    private String lastName;
    @Column
    private String email;
    @Column
    private Integer age;
    //使用@OneToMany来映射一对多的关联关系,使用@JoinColumn映射外键列的名称,使用@OneToMany的fetch属性来修改默认的加载策略
    //可以使用@OneToMany的cascade属性来修改默认的删除策略,他会把多方外键设置为空,然后再删除
    @JoinColumn(name = "order_id")
    @OneToMany(fetch = FetchType.EAGER,cascade = {CascadeType.REMOVE})
    List<Order> orders = new ArrayList<>();
}

设计Order

@Data
@Entity
@Table(name = "t_order")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;
    @Column
    private String orderName;
}

映射的效果就是表customer中有order的外键

单向1-n关联关系执行保存时,一定会多出UPDATE语句,因为多方在插入时不会同时插入外键列

关联关系之双向一对多和双向多对一

其实他们是一回事,从左看是一对多,从右看就是多对一了

设计客户Customer

@Data
@Entity
@Table(name = "t_customer")
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;
    @Column
    private String lastName;
    @Column
    private String email;
    @Column
    private Integer age;
    //使用@OneToMany来映射一对多的关联关系,使用@JoinColumn映射外键列的名称
    @JoinColumn(name = "order_id")
    @OneToMany
    List<Order> orders = new ArrayList<>();
}

设计订单Order

@Data
@Entity
@Table(name = "t_order")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;
    @Column
    private String orderName;
   //使用@ManyToOne来映射多对一的关联关系,使用@JoinColumn来映射外键
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "customer_id")
    private Customer customer;
}

在设计类时,需要注意的是,在双向一对多的关联关系中,关联对象的@JoinColumn映射的外键列名要一致,这里我们都设置为customer_id,双方都要去维护外键

我们插入一条数据
若是双向1- n的关联关系,在执行保存时,如果先保存多方,再保存一方,会多出n条sql语句,原因是

在保存多方时,他想给多方的外键设置值,但是此时还没有一方的数据,所以先给他设置为空,然后再保存我们的一方,保存完了之后,多方要去维护外键,发送一条update语句去修改这个外键的值,然后一方他也要去维护外键的值,他也要发送update语句,很显然,这是非常不好的

若先保存一方,再保存多方

这样就相当于当你保存多方,在插入外键时,发现已经有值了,多方已经维护了外键,只需要一方去维护一下外键就可以了,发送一条update语句

在进行双向1 -n关联关系时,建议使用多方来维护关联关系,也就是维护外键,一方就不维护了,这样就可以有效地减少sql的发送,sql发送得少,性能也提高了嘛

这样的话,那如何让一方放弃维护关联关系呢?

@Data
@Entity
@Table(name = "t_customer")
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;
    @Column
    private String lastName;
    @Column
    private String email;
    @Column
    private Integer age;
    //使用@OneToMany来映射一对多的关联关系,使用@JoinColumn映射外键列的名称,使用mappedBy表示我不维护关联关系了,由customer来维护
//    @JoinColumn(name = "customer_id")
    @OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.REMOVE,mappedBy = "customer")
    List<Order> orders = new ArrayList<>();
}

使用mappedBy表示我一方不维护关联关系了,由你多方来维护,mappedBy的值就是多方@ManyToOne的字段,这里需要注意的是,一方使用了mappedBy属性就不能使用映射外键列的注解,@JoinColumn(name = “customer_id”) ,不然会报错

表映射效果,以上映射到表都是这样的
在这里插入图片描述在这里插入图片描述

关联关系之双向一对一

举例:一个部门只有一个经理,一个经理也只能管一个部门
设计经理Manager

@Data
@Entity
@Table(name = "t_manager")
public class Manager {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;
    @Column(name = "mgr_name")
    private String mgrName;
    //对于不维护关联关系,即没有外键的一方,使用@OneToOne来映射,需要设置mappedBy = "manager"放弃维护
    @OneToOne(mappedBy = "manager")
    private Department department;
}

设计部门Department

@Data
@Entity
@Table(name = "t_department")
public class Department {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;
    private String deptName;
    //使用@OneToMany来映射1- 1的关联关系,注意1-1的关联关系,所以需要添加unique = true
    @JoinColumn(name = "mgr_id",unique = true)
    @OneToOne
    private Manager manager;
}

双向一对一,建议先保存不维护关系的一方,即没有外键的一方,这样不会多出update语句,因为,如果你先保存维护外键的一方,当插入外键列时,发现不维护外键的一方为空,他就会先给你设置为空,然后等你不维护外键的一方插入完有值之后,再发送一条update语句进行修改那个外键

表映射效果
在这里插入图片描述在这里插入图片描述
这种虽然和上面映射的类似,但是这个外键时唯一的,外键值不能重复,所以才称为一对一

关联关系之双向多对多

举例:一个类别有多个商品,同样,一个商品也属于多个类别
设计商品Item

@Data
@Entity
@Table(name = "t_item")
public class Item {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;
    @Column(name = "item_name")
    private String itemName;
    //name是映射中间表的名字,@JoinTable是映射到中间表,joinColumns就是中间表中列的名字,一个是当前类映射到数据库中的主键对应的外键,
    // referencedColumnName是我指向当前表的主键,inverseJoinColumns是我关联的那个对象在中间表中的外键,他指向Category的主键
    @JoinTable(name = "ITEM_CATEGORY",joinColumns = {@JoinColumn(name = "ITEM_ID",referencedColumnName = "ID")},
    inverseJoinColumns = {@JoinColumn(name = "CATEGORY_ID",referencedColumnName = "ID")})
    @ManyToMany
    List<Category> categories = new ArrayList<>();
}

设计分类Category

@Data
@Entity
@Table(name = "t_category")
public class Category {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name = "category_name")
    private String categoryName;
    //放弃外键的维护
    @ManyToMany(mappedBy = "categories")
    private List<Item> itemList = new ArrayList<>();
}

表映射效果
在这里插入图片描述在这里插入图片描述在这里插入图片描述

设计表总结

1、将一个类映射到数据库表使用@Entity,指定表名使用@Table(name = “你想映射成的表名”)
2、主键映射使用@Id,@GeneratedValue(strategy = GenerationType.IDENTITY),主键生成策略可以使用auto默认的
3、实体类中字段映射为表中列名使用@Column(name = “映射到表中的列名”)
4、 在关联关系中,不能双方都去维护外键,一般都是多方维护,另外一方使用mappedBy,值为关联的那个类中的关联对象的字段,意为放弃关联关系的维护
5、如果不清楚懒加载和及时加载的区别,那就都使用懒加载吧,配置一对多,多对一注解属性fetch = FetchType.LAZY,利大于弊
6、在其中一方放弃维护关联关系时,这一方不能使用映射外键列名注解@JoinColumn,因为他已经放弃了维护外键,不能有外键了
7、在双向一对多关联关系中,删除这种情况很特殊,假如你要删除一方,而多方有数据的外键有值得,这时你删不掉;你可以在一方@OneToMany配置属性cascade = CascadeType.ALL,当你删除一方时,只要多方的外键是你删除一方这条数据的主键,那么会将一方相关的全部删除,有点危险哦 ,如果你配置了cascade = CascadeType.REMOVE这种,他会先将多方中的外键设置为空,然后再删除
另外就是@ManyToMany多对多关联关系中,映射中间表的一些注解的意思,上面写得很清楚了。

欢迎各位大佬吐槽,谢谢

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值