long may the sunshine.

今天的我拿起键盘就是猛敲代码。

果然,十分钟后各种 JPA 报错开始了。跟新手党一样,看到一个错误就解决一个,没有好好思考为什么会出现这样的错误。

于是乎,遇到一个解决一个,解决一个又遇到一个,经过数十个报错的来回起伏。

敏锐的我发现苗头有些不对。全靠脑细胞的记忆,以及开始对第一个错误的解决过程开始模糊不清了。

最后,我采用了《数据库 ER 图》的方式,重新开始分析、梳理。

也就是本文的初衷。

当我写到最后的时候。我的 Junit 用例全部跑通了。赞。

以下是正文,稍微有点。。。。。。。。。。。。。长。


01 数据库 ER 图

ER 图概念

  1. 实体 entity:用矩形表示,数据模型中的数据对象。

  2. 属性 attribute:用椭圆形表示,数据对象所具有的属性(所具有的列)。其中唯一属性 unique attribute,用下划线表示。

  3. 关系 relationshop:用菱形表示,数据对象与数据对象之间的联系。

假设有两个实体集 A、B,它们有以下三种关联关系。

  1. 一对一 1:1

    1. A 的每个实体至多与 B 的一个实体有关系。

    2. B 的每个实体至多与 A 的一个实体有关系。

    3. 满足以上两点,即 A 与 B 的关系是一对一。

  2. 一对多 1:N

    1. A 的每个实体至少与 B 的 N(N>0)个实体有关系。

    2. B 的每个实体至多与 A 的一个实体有关系。

    3. 满足以上两点,即 A 与 B 的关系是一对多,B 与 A 的关系是多对一。

  3. 多对多 M:N

    1. A 的每个实体至少与 B 的 M(M>0)个实体有关系。

    2. B 的每个实体至少与 A 的 N(N>0)个实体有关系。

    3. 满足以上两点,即 A 与 B 的关系是多对多。


02 JPA 关联

在 JPA 中分别使用 @OneToOne、@OneToMany、@ManyToOne、@ManyToMany 注解表示一对一、一对多,多对一、多对多三种关联关系。

OneToOne

  1. targetEntity,作为关联目标的实体类。

  2. cascade,必须级联到关联目标的操作。

    1. ALL,级联所有操作。

    2. PERSIST,级联保存操作。

    3. MERGE,级联修改操作。

    4. REMOVE,级联删除操作。

    5. REFRESH,级联刷新操作。

    6. DETACH,级联分离操作。(2.0 版本开始支持)

  3. fetch,关联是延迟加载还是必须立刻获取。

  4. optional,关联是否为可选。

  5. mappedBy,拥有关系的字段。仅在关联的反侧(非所有权)指定此元素。

  6. orphanRemoval,是否将删除操作应用于已从关系中删除的实体,以及是否将删除操作级联到那些实体。

OneToMany

targetEntity、cascade、fetch、mappedBy、orphanRemoval

ManyToOne

targetEntity、cascade、fetch、orphanRemoval

ManyToMany

targetEntity、cascade、fetch、mappedBy

在以上关联注解的使用过程中,还需要 @JoinColumn 指定实体关联、元素集合的列。

例如:@ManyToOne@JoinColumn(name="ADDR_ID")public Address getAddress() { return address; }@OneToMany@JoinColumn(name="CUST_ID")public SetgetOrders() {return orders;}

03 分析

图 A - ER 图

本案例有四张数据库表,分别为导购员、商品数据、订单主数据,以及订单明细数据。(如上图所示)

导购员、商品数据是基础数据表,即不主动关联其他的实体集。

商品主数据,包含两种关联关系。

  1. 与导购员之间的关系是多对一。即 @ManyToOne,注意这里只需要级联刷新操作即可。

  2. 与订单明细数据的关系是一对多。即@OneToMany,注意这里需要级联保存、修改、删除、刷新所有的操作。

商品明细数据,也包含两种关联关系。

  1. 与商品数据之间的关系是多对一。即 @ManyToOne,注意这里只需要级联刷新操作即可。

  2. 与订单主数据的关系是多对一。即@ManyToOne,注意这里需要级联保存、修改、删除、刷新所有的操作。


04 示例代码

导购数据 UscGuideEntity

package cn.live.opos.center.entity;// 省略 import/** * usc_guide. *  * @author chenxinjie * @date 2020-08-01 */@Entity@Table(name = "usc_guide", uniqueConstraints = { @UniqueConstraint(columnNames = "no") })public class UscGuideEntity implements Serializable {  private static final long serialVersionUID = -5648617800765002770L;  @Id  @GeneratedValue(strategy = GenerationType.AUTO, generator = "jpa-uuid")  @GenericGenerator(name = "jpa-uuid", strategy = "org.hibernate.id.UUIDGenerator")  @Column(name = "id", length = 36)  private String id;  @Column(name = "no", length = 20, nullable = false)  private String no;  @Column(name = "name", length = 40, nullable = false)  private String name;  @Column(name = "gender", columnDefinition = "int default 0", nullable = false)  private int gender;  @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")  @Temporal(TemporalType.TIMESTAMP)  @Column(name = "ts", columnDefinition = "timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP() ON UPDATE CURRENT_TIMESTAMP()", nullable = false)  private Date ts;  // 省略 get/set 方法}

商品数据 PscSkuEntity

package cn.live.opos.center.entity;// 省略 import@Entity@Table(name = "psc_sku", uniqueConstraints = { @UniqueConstraint(columnNames = "sku") })public class PscSkuEntity implements Serializable {  private static final long serialVersionUID = 8904367725209990433L;  @Id  @GeneratedValue(strategy = GenerationType.AUTO, generator = "jpa-uuid")  @GenericGenerator(name = "jpa-uuid", strategy = "org.hibernate.id.UUIDGenerator")  @Column(name = "id", length = 36)  private String id;  @Column(name = "sku", length = 50, nullable = false)  private String sku;  @Column(name = "product_no", length = 40, nullable = false)  private String productNo;  @Column(name = "product_name", length = 100, nullable = false)  private String productName;  @Column(name = "color_no", precision = 4, scale = 0, nullable = false)  private int colorNo;  @Column(name = "color_name", nullable = false)  private String colorName;  @Column(name = "size_no", precision = 4, scale = 0, nullable = false)  private int sizeNo;  @Column(name = "size_name", nullable = false)  private String sizeName;  @Column(name = "tag_price", precision = 10, scale = 0, nullable = false)  private int tagPrice;  @Column(name = "retail_price", precision = 10, scale = 0, nullable = false)  private int retailPrice;  @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")  @Temporal(TemporalType.TIMESTAMP)  @Column(name = "ts", columnDefinition = "timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP() ON UPDATE CURRENT_TIMESTAMP()", nullable = false)  private Date ts;  // 省略 get/set 方法}

订单主数据 OscOrderEntity

package cn.live.opos.center.entity;// 省略 import@Entity@EntityListeners(AuditingEntityListener.class)@Table(name = "osc_order", uniqueConstraints = { @UniqueConstraint(columnNames = "order_no") })public class OscOrderEntity implements Serializable {  private static final long serialVersionUID = -4409502876337140593L;  @Id  @GeneratedValue(strategy = GenerationType.AUTO, generator = "jpa-uuid")  @GenericGenerator(name = "jpa-uuid", strategy = "org.hibernate.id.UUIDGenerator")  @Column(name = "id", length = 36)  private String id;  @Column(name = "order_no", length = 40, nullable = false)  private String orderNo;  @CreatedDate  @JsonFormat(pattern = "yyyy-MM-dd")  @Temporal(TemporalType.DATE)  @Column(name = "order_date", nullable = false)  private Date orderDate;  /**   * 1: sell of goods. 2: return of goods.   */  @Column(name = "order_type", nullable = false)  private int orderType;  @Column(name = "order_status", nullable = false)  private int orderStatus;  @Column(name = "num", precision = 5, scale = 0, nullable = false)  private int num;  @Column(name = "total", precision = 10, scale = 0, nullable = false)  private int total;  @Column(name = "guide_no", length = 20, nullable = false)  private String guideNo;  @LastModifiedDate  @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")  @Temporal(TemporalType.TIMESTAMP)  @Column(name = "ts", columnDefinition = "timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP() ON UPDATE CURRENT_TIMESTAMP()", nullable = false)  private Date ts;  @OneToMany(targetEntity = OscOrderItemEntity.class, cascade = CascadeType.ALL, fetch = FetchType.EAGER)  @JoinColumn(name = "order_no", referencedColumnName = "order_no", insertable = false, updatable = false)  private List orderItems;  @ManyToOne(targetEntity = UscGuideEntity.class, cascade = CascadeType.REFRESH)  @JoinColumn(name = "guide_no", referencedColumnName = "no", insertable = false, updatable = false)  private UscGuideEntity guideEntity;  // 省略 get/set 方法}

订单明细数据 OscOrderItemEntity

package cn.live.opos.center.entity;// 省略 import@Entity@EntityListeners(AuditingEntityListener.class)@Table(name = "osc_order_item", uniqueConstraints = {    @UniqueConstraint(columnNames = { "order_no", "sku" }) })public class OscOrderItemEntity implements Serializable {  private static final long serialVersionUID = -7331381906879927968L;  @Id  @GeneratedValue(strategy = GenerationType.AUTO, generator = "jpa-uuid")  @GenericGenerator(name = "jpa-uuid", strategy = "org.hibernate.id.UUIDGenerator")  @Column(name = "id", length = 36)  private String id;    @Column(name = "order_no", length = 40, nullable = false)  private String orderNo;  @Column(name = "sku", length = 50, nullable = false)  private String sku;  @Column(name = "num", precision = 5, scale = 0, nullable = false)  private int num;  @Column(name = "tag_price", precision = 10, scale = 0, nullable = false)  private int tagPrice;  @Column(name = "retail_price", precision = 10, scale = 0, nullable = false)  private int retailPrice;  @Column(name = "total", precision = 10, scale = 0, nullable = false)  private int total;  @LastModifiedDate  @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")  @Temporal(TemporalType.TIMESTAMP)  @Column(name = "ts", columnDefinition = "timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP() ON UPDATE CURRENT_TIMESTAMP()", nullable = false)  private Date ts;  @ManyToOne(targetEntity = OscOrderEntity.class, cascade = CascadeType.ALL)  @JoinColumn(name = "order_no", referencedColumnName = "order_no", insertable = false, updatable = false)  private OscOrderEntity orderEntity;  @ManyToOne(targetEntity = PscSkuEntity.class, cascade = CascadeType.REFRESH)  @JoinColumn(name = "sku", referencedColumnName = "sku", insertable = false, updatable = false)  private PscSkuEntity skuEntity;  // 省略 get/set 方法}

05 效果

使用 JPA 查询一个订单主数据,JPA 会自动将配置好的其他表的数据实体自动查询出来。

也就是,省略了查询导购员、订单明细数据、商品数据三条 SQL 语句。

PS. 完整示例代码,见 https://github.com/FoamValue/oPos.git


06 小结

今天先写到这里。

夜深了,让我们下周再见。?

这个周末,又一次成功“强迫”自己学习。

感谢各位小伙伴的阅读,这里是一个技术人的学习与分享。

jpa onetoone_拥抱开源从表设计到 JPA 实现相关推荐

  1. java jpa @joincolumn 字段不为空_拥抱开源从表设计到 JPA 实现

    long may the sunshine. 今天的我拿起键盘就是猛敲代码. 果然,十分钟后各种 JPA 报错开始了.跟新手党一样,看到一个错误就解决一个,没有好好思考为什么会出现这样的错误. 于是乎 ...

  2. 开源物联网平台ThingsBoard数据库40张数据表设计一览

    开源物联网平台ThingsBoard数据库40张数据表设计一览 1 ThingsBoard数据库总览 1.1 数据库信息 1.1.1 数据库名称 1.1.3 数据库用户名及密码 1.1.3 数据库表 ...

  3. 腾讯拥抱开源:首次公布开源路线图,技术研发向共享、复用和开源迈进

    整理 | 夕颜 出品 | AI科技大本营(ID:rgznai100) 导读:去年,知乎上一篇讨论腾讯技术的帖子异常火爆,讨论的主题是当下(2018 年)腾讯的技术建设是否处于落后同体量公司的状态,这篇 ...

  4. 拥抱开源,Office 365开发迎来新时代

    前言 作为全球最大的开放源代码托管平台,Github在上周迎来了它的十岁生日.自从2008年正式上线以来,Github上面汇聚了数以千万计的开发人员和各种项目,它几乎成为了开源的代名词和风向标,各大软 ...

  5. 万字归纳总结 | 数据库表设计与SQL编写技巧

    点击上方"朱小厮的博客",选择"设为星标" 后台回复"加群"加入公众号专属技术群 前言 随着移动云平台系统业务不断增长,必然需要对各系统进行 ...

  6. 「拥抱开源, 又见 .NET」系列第三次线下活动简报

    「拥抱开源, 又见 .NET」 随着 .NET Core的发布和开源,.NET又重新回到人们的视野.自2016年 .NET Core 1.0 发布以来,其强大的生命力让越来越多技术爱好者对她的未来满怀 ...

  7. 西安活动 | 2019年1月13号 拥抱开源, 又见.NET 线下交流活动报名进行中

    随着.NET Core的发布和开源,.NET又重新回到人们的视野..NET Core的下个3.0即将release,加入非常多的新功能,越来越拥抱变化,DevOps和Microservice的最佳实践 ...

  8. 拥抱开源, Office 365开发迎来新时代

    这个话题我曾经写过文章,也在一些场合做过专题分享.今天换一种方式,你可以直接点击下面这个小程序,用十分钟左右的时间,听我再讲一讲吧. 你需要在微信里面才能看到下面的小程序链接,并且可以直接点击 你可以 ...

  9. 微软正在用实际行动告诉你: 拥抱开源,微软是认真的

    2017年4月19日至20日,由工业和信息化部指导.中国信息通信研究院主办.云计算开源产业联盟承办的"全球云计算开源峰会"在国家会议中心举行.微软.NET CORE开发平台荣获由峰 ...

最新文章

  1. SliverLight注册字典转换器方法
  2. 一次毕生难忘的 Java 内存泄漏排查经历
  3. 读书笔记_Effective_C++_条款三十一:将文件间的编译依存关系降至最低(第二部分)...
  4. 查md5或者sha1值
  5. 迁移到php7,迁移PHP版本到PHP7
  6. nagios学习笔记(二)
  7. 卖萌屋福利场:《机器阅读理解》免费送送送!
  8. 解决the resource is not on the build path of a java project
  9. linux四剑客-grep/find/sed/awk/详解-技术流ken
  10. 猫和老鼠服务器维护多久结束,猫和老鼠手游关服公告 告别是为了每次更好的遇见!...
  11. Linus 07年在 Google讲座介绍Git的特点和设计思路
  12. 题目1140:八皇后
  13. 在aarch64-himix100-linux-gcc下cmake报错(The C compiler identification is unknown)
  14. 自动驾驶_感知_目标检测(基于图像)
  15. 科研神器----数据提取软件WebPlotDigitizer的使用
  16. Shopee跨境电商开店高频问题解答
  17. 4.2.5 求解幂集问题
  18. 搭建OA系统运维需要了解的知识?
  19. 免费得到高程地图的方法
  20. Win10彻底删除Windows.old文件夹

热门文章

  1. 快速搭建实验环境:使用 Terraform 部署 Proxmox 虚拟机
  2. 存储基础:磁盘 IO 为什么总叫你对齐?
  3. 近7万新冠域名一半是钓鱼网站?以色列老牌安全厂商Check Point推出全端保护新战略
  4. VMware为全球数字化基础架构提供原生安全
  5. 详解云计算、大数据和人工智能的区别与联系
  6. php 动态 控件,PHP技术在动态网页表单控件提取中的应用研究
  7. 前台传String日期格式后台用Date类型接收
  8. Springboot2.x +JPA 集成 Apache ShardingSphere 同库分表
  9. 更改默认软件下载的路径
  10. CentOS7.4下载与安装