学习Spring有两周时间了 , 个人觉得服务端主要实现的是数据关系的维护和数据结构的制定 , 以及由业务需求产生的CRUD , 只要保证对前端提供的接口稳定高效响应 , 具体的前端实现完全不关心.

这个是接触后端的一个感受 , Spring boot使用了特定的方式来进行配置 ,大大简化了后端开发人员的开发工作量 ,比如JPA:用来操作实体对象,执行CRUD操作,框架在后台替我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来 ,此时数据之间的关系维护和数据结构的制定就显得尤为关键 , 下面记录数据表对应关系中的常见关系:一对多关系.

数据表关系

下面用实际场景简单理解数据表之间的关系

一对一:我有一个身份证号 ;
一对多:我有多张银行卡;
多对多:我是招行、交行、建行的客户,但是这些银行用户均过亿。

一对多双向关联

下面以订单order和订单项orderitem来展示

创建订单实体类,代码如下:

package learn.jpa.entity;

import java.util.HashSet;
import java.util.Set; import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany; /**
* 订单
*/
@Entity // 定义类为实体类
public class Order { private String orderid;
private float amount = 0f;
private Set<OrderItem> item = new HashSet<OrderItem>(); @Id // 实体标识符,因为是字符串类型,所有不能用 @GeneratedValue,只能人为的赋值
@Column(length=20)
public String getOrderid() {
return orderid;
}
public void setOrderid(String orderid) {
this.orderid = orderid;
}
@Column(nullable = false)
public float getAmount() {
return amount;
}
public void setAmount(float amount) {
this.amount = amount;
}
@OneToMany(cascade={CascadeType.REFRESH,CascadeType.PERSIST,CascadeType.MERGE})
public Set<OrderItem> getItem() {
return item;
}
public void setItem(Set<OrderItem> item) {
this.item = item;
} }
/**
* 1 - N
* 多的一端为关系维护端,关系维护端负责外键记录的更新
*
*/

创建订单项实体类,代码如下

package learn.jpa.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id; /**
* 订单项
*/
@Entity // 定义类为实体类
public class OrderItem { private int id;
private String productName;
private float sellPrice = 0f;
private Order order; @Id // 实体标识符
@GeneratedValue // 主键自动增长
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
} @Column(length=40,nullable=false)
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
} @Column(nullable=false)
public float getSellPrice() {
return sellPrice;
}
public void setSellPrice(float sellPrice) {
this.sellPrice = sellPrice;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
}

注解:

1、@OneToMany(fetch=FetchType,cascade=CascadeType)

@OneToMany描述一个一对多的关联,该属性应该为集体类型,在数据库中并没有实际字段.

fetch:表示该属性的读取策略,有EAGER和LAZY两种,分别表示主支抓取和延迟加载,默认为EAGER.

cascade:表示级联操作策略,对于OneToMany类型的关联非常重要,通常该实体更新或删除时,其关联的实体也应当被更新或删除

(1)、CascadeType.MERGE级联更新:若items属性修改了那么order对象保存时同时修改items里的对象。对应EntityManager的merge方法

(2)、CascadeType.PERSIST级联刷新:获取order对象里也同时也重新获取最新的items时的对象。对应EntityManager的refresh(object)方法有效。即会重新查询数据库里的最新数据

(3)、CascadeType.REFRESH级联保存:对order对象保存时也对items里的对象也会保存。对应EntityManager的presist方法

(4)、CascadeType.REMOVE级联删除:对order对象删除也对items里的对象也会删除。对应EntityManager的remove方法

CascadeType.PERSIST只有A类新增时,会级联B对象新增。若B对象在数据库存(跟新)在则抛异常(让B变为持久态)

CascadeType.MERGE指A类新增或者变化,会级联B对象(新增或者变化)

CascadeType.REMOVE只有A类删除时,会级联删除B类;

CascadeType.ALL包含所有;

综上:大多数情况用CascadeType.MERGE就能达到级联跟新又不报错,用CascadeType.ALL时要斟酌下CascadeType.REMOVE

optional:是否允许该字段为null,该属性应该根据数据库表的外键约束来确定,默认为true

一对多延迟加载与关系维护

订单实体类,代码:

package learn.jpa.entity;

import java.util.HashSet;
import java.util.Set; import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table; /**
* 订单
*/
@Entity // 定义类为实体类
@Table(name="orders")
public class Order { private String orderid;
private float amount = 0f;
private Set<OrderItem> item = new HashSet<OrderItem>(); @Id // 实体标识符,因为是字符串类型,所有不能用 @GeneratedValue,只能人为的赋值
@Column(length=20)
public String getOrderid() {
return orderid;
}
public void setOrderid(String orderid) {
this.orderid = orderid;
}
@Column(nullable = false)
public float getAmount() {
return amount;
}
public void setAmount(float amount) {
this.amount = amount;
}
/**
* 如果是一对多或多对多 fetch 默认是延迟加载,反之是立即加载
* mappedBy="order" 表示由实体 OrderItem 中的 order 属性维护
* @return
*/
@OneToMany(cascade={CascadeType.REFRESH,CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REMOVE},
fetch=FetchType.LAZY,mappedBy="order")
public Set<OrderItem> getItem() {
return item;
}
public void setItem(Set<OrderItem> item) {
this.item = item;
} public void addOrderItem(OrderItem orderItem){
orderItem.setOrder(this);
this.item.add(orderItem);
} }
/**
* 1 - N
* 多的一端为关系维护端,关系维护端负责外键记录的更新
*
*/

mappedBy只有在双向关联时,才会使用这个属性

mappedBy=”另一方的关系引用属性”

订单项实体类,代码:

package learn.jpa.entity;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table; /**
* 订单项
*/
@Entity // 定义类为实体类
public class OrderItem { private int id;
private String productName;
private float sellPrice = 0f;
private Order order; @Id // 实体标识符
@GeneratedValue // 主键自动增长
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
} @Column(length=40,nullable=false)
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
} @Column(nullable=false)
public float getSellPrice() {
return sellPrice;
}
public void setSellPrice(float sellPrice) {
this.sellPrice = sellPrice;
}
@ManyToOne(cascade={CascadeType.MERGE,CascadeType.REFRESH},fetch=FetchType.EAGER,optional=false)
@JoinColumn(name="order_id")
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
}

joinColumns属性表示,在保存关系中的表中,所保存关联关系的外键的字段。并配合@JoinColumn标记使用。

小结

理解关联表中存储的关系对含义, 记下使用的套路基本上就没什么问题了 ,下篇文章将记录多对多双向关联与级联操作 .

JPA中的一对多双向关联与级联操作的更多相关文章

  1. JPA学习---第九节:JPA中的一对多双向关联与级联操作

    一.一对多双向关联与级联操作 1.创建项目,配置文件代码如下: <?xml version="1.0" encoding="UTF-8"?> < ...

  2. JPA学习---第十一节:JPA中的多对多双向关联实体定义与注解设置及操作

    1.定义实体类,代码如下: (1).学生实体类: package learn.jpa.entity; import java.util.HashSet; import java.util.Set; i ...

  3. Hibernate从入门到精通(九)一对多双向关联映射

    上次的博文Hibernate从入门到精通(八)一对多单向关联映射中,我们讲解了一下一对多单向映射的相关内容,这次我们讲解一下一对多双向映射的相关内容. 一对多双向关联映射 一对多双向关联映射,即在一的 ...

  4. Hibernate(九)一对多双向关联映射

    上次的博文Hibernate从入门到精通(八)一对多单向关联映射中,我们讲解了一下一对多单向映射的相关 内容,这次我们讲解一下一对多双向映射的相关内容. 一对多双向关联映射 一对多双向关联映 射,即在 ...

  5. Hibernate 一对多双向关联Demo

    以Classes[班级]和Student[学生]为例的Demo //Classes.java public class Classes implements Serializable { privat ...

  6. hibernate 一对多双向关联 详解

    一.解析: 1.  一对多双向关联也就是说,在加载班级时,能够知道这个班级所有的学生. 同时,在加载学生时,也能够知道这个学生所在的班级. 2.我们知道,一对多关联映射和多对一关联映射是一样的,都是在 ...

  7. Hibernate中用注解配置一对多双向关联和多对一单向关联

    Hibernate中用注解配置一对多双向关联和多对一单向关联 Hibernate提供了Hibernate Annotations扩展包,使用注解完成映射.在Hibernate3.3之前,需单独下载注解 ...

  8. SpringData_04_ JPA中的一对多

    1.JPA中的一对多 在一对多关系中,我们习惯把一的一方称之为主表,把多的一方称之为从表.在数据库中建立一对多的关系,需要使用数据库的外键约束. 什么是外键? 指的是从表中有一列,取值参照主表的主键, ...

  9. grails一对多双向关联

    前面分享了一些学习grails的心得,可是grails的知识还远不止这些,这次整理了一点有关grails一对多双向关联关系的知识.我认为这样的关联用的地方太多了,这次准备的样例是城市和区域的相关样例. ...

随机推荐

  1. 开发npm模块经验总结

    1.在windows下开发的package.json的bin链接的全局命令可能会在linux下报错:“没有那个文件或目录”之类的错误...此时可以在linux下用vim打开bin链接的js文件,设置s ...

  2. phpcms功能列表

    上1 站点首页 就是前台首页 会员中心 跳到会员中心页面 搜索 新闻,图片等文档搜索 锁屏 锁住账号 Phpcms 官网 授权 官网查询 支持论坛 官网论坛 帮助 官网帮助 上2 我的面板 个人信息 ...

  3. FolderSync Instant sync 即时同步

    Folderpairs - Edit folderpair - Sync options - Instant sync  Select this for instant sync on change. ...

  4. sqlserver存储过程循环写法

    用游标,和WHILE可以遍历您的查询中的每一条记录并将要求的字段传给变量进行相应的处理==================DECLARE @A1 VARCHAR(10),@A2 VARCHAR(10) ...

  5. GlobalGetAtomName GlobalDeleteAtom 引用 WinAPI: AddAtom、DeleteAtom、FindAtom、GetAtomName、GlobalAddAtom、GlobalDeleteAtom、GlobalFindAtom、GlobalGetAtomName

    http://www.cnblogs.com/del/archive/2008/02/28/1085124.html 这是储存字符串的一组 API.通过 AddAtom 储存一个字符串, 返回一个 I ...

  6. .Net高级技术——对象序列化

    对象序列化 “序列化是将一个对象保存到存储介质上或者将对象进行转换使之能够在网络上传送的行为”.通俗一点的解释,序列化就是把一个对象保存到一个文件或数据库字段中去,反序列化就是从文件或者数据库中取出数 ...

  7. Adding an instance to a MEF container

    How can you add an already created instance to a MEF container/cataloge to use when resolving Import ...

  8. 深入理解 Java中的 流 (Stream)

    首先,流是什么? 流是个抽象的概念.是对输入输出设备的抽象,Java程序中,对于数据的输入/输出操作都是以"流"的方式进行.设备能够是文件,网络,内存等. 流具有方向性,至于是输入 ...

  9. 用Qemu模拟vexpress-a9 (一) --- 搭建Linux kernel调试环境

    参考: http://blog.csdn.net/linyt/article/details/42504975 环境介绍: Win7 64 + Vmware 11 + ubuntu14.04 32 u ...

  10. Android实例剖析笔记(一)

    摘要:用实例讲解Andriod的开发过程 开卷语 俗话说,“熟读唐诗三百首,不会作诗也会吟”.最近收集了很多Android的示例代码,从这些代码的阅读和实验中学习到很多知识,从而产生写这个系列的打算, ...