jpa onetoone_拥抱开源从表设计到 JPA 实现
long may the sunshine.
今天的我拿起键盘就是猛敲代码。
果然,十分钟后各种 JPA 报错开始了。跟新手党一样,看到一个错误就解决一个,没有好好思考为什么会出现这样的错误。
于是乎,遇到一个解决一个,解决一个又遇到一个,经过数十个报错的来回起伏。
敏锐的我发现苗头有些不对。全靠脑细胞的记忆,以及开始对第一个错误的解决过程开始模糊不清了。
最后,我采用了《数据库 ER 图》的方式,重新开始分析、梳理。
也就是本文的初衷。
当我写到最后的时候。我的 Junit 用例全部跑通了。赞。
以下是正文,稍微有点。。。。。。。。。。。。。长。
01 数据库 ER 图
ER 图概念
实体 entity:用矩形表示,数据模型中的数据对象。
属性 attribute:用椭圆形表示,数据对象所具有的属性(所具有的列)。其中唯一属性 unique attribute,用下划线表示。
关系 relationshop:用菱形表示,数据对象与数据对象之间的联系。
假设有两个实体集 A、B,它们有以下三种关联关系。
一对一 1:1
A 的每个实体至多与 B 的一个实体有关系。
B 的每个实体至多与 A 的一个实体有关系。
满足以上两点,即 A 与 B 的关系是一对一。
一对多 1:N
A 的每个实体至少与 B 的 N(N>0)个实体有关系。
B 的每个实体至多与 A 的一个实体有关系。
满足以上两点,即 A 与 B 的关系是一对多,B 与 A 的关系是多对一。
多对多 M:N
A 的每个实体至少与 B 的 M(M>0)个实体有关系。
B 的每个实体至少与 A 的 N(N>0)个实体有关系。
满足以上两点,即 A 与 B 的关系是多对多。
02 JPA 关联
在 JPA 中分别使用 @OneToOne、@OneToMany、@ManyToOne、@ManyToMany 注解表示一对一、一对多,多对一、多对多三种关联关系。
OneToOne
targetEntity,作为关联目标的实体类。
cascade,必须级联到关联目标的操作。
ALL,级联所有操作。
PERSIST,级联保存操作。
MERGE,级联修改操作。
REMOVE,级联删除操作。
REFRESH,级联刷新操作。
DETACH,级联分离操作。(2.0 版本开始支持)
fetch,关联是延迟加载还是必须立刻获取。
optional,关联是否为可选。
mappedBy,拥有关系的字段。仅在关联的反侧(非所有权)指定此元素。
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 图
本案例有四张数据库表,分别为导购员、商品数据、订单主数据,以及订单明细数据。(如上图所示)
导购员、商品数据是基础数据表,即不主动关联其他的实体集。
商品主数据,包含两种关联关系。
与导购员之间的关系是多对一。即 @ManyToOne,注意这里只需要级联刷新操作即可。
与订单明细数据的关系是一对多。即@OneToMany,注意这里需要级联保存、修改、删除、刷新所有的操作。
商品明细数据,也包含两种关联关系。
与商品数据之间的关系是多对一。即 @ManyToOne,注意这里只需要级联刷新操作即可。
与订单主数据的关系是多对一。即@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 实现相关推荐
- java jpa @joincolumn 字段不为空_拥抱开源从表设计到 JPA 实现
long may the sunshine. 今天的我拿起键盘就是猛敲代码. 果然,十分钟后各种 JPA 报错开始了.跟新手党一样,看到一个错误就解决一个,没有好好思考为什么会出现这样的错误. 于是乎 ...
- 开源物联网平台ThingsBoard数据库40张数据表设计一览
开源物联网平台ThingsBoard数据库40张数据表设计一览 1 ThingsBoard数据库总览 1.1 数据库信息 1.1.1 数据库名称 1.1.3 数据库用户名及密码 1.1.3 数据库表 ...
- 腾讯拥抱开源:首次公布开源路线图,技术研发向共享、复用和开源迈进
整理 | 夕颜 出品 | AI科技大本营(ID:rgznai100) 导读:去年,知乎上一篇讨论腾讯技术的帖子异常火爆,讨论的主题是当下(2018 年)腾讯的技术建设是否处于落后同体量公司的状态,这篇 ...
- 拥抱开源,Office 365开发迎来新时代
前言 作为全球最大的开放源代码托管平台,Github在上周迎来了它的十岁生日.自从2008年正式上线以来,Github上面汇聚了数以千万计的开发人员和各种项目,它几乎成为了开源的代名词和风向标,各大软 ...
- 万字归纳总结 | 数据库表设计与SQL编写技巧
点击上方"朱小厮的博客",选择"设为星标" 后台回复"加群"加入公众号专属技术群 前言 随着移动云平台系统业务不断增长,必然需要对各系统进行 ...
- 「拥抱开源, 又见 .NET」系列第三次线下活动简报
「拥抱开源, 又见 .NET」 随着 .NET Core的发布和开源,.NET又重新回到人们的视野.自2016年 .NET Core 1.0 发布以来,其强大的生命力让越来越多技术爱好者对她的未来满怀 ...
- 西安活动 | 2019年1月13号 拥抱开源, 又见.NET 线下交流活动报名进行中
随着.NET Core的发布和开源,.NET又重新回到人们的视野..NET Core的下个3.0即将release,加入非常多的新功能,越来越拥抱变化,DevOps和Microservice的最佳实践 ...
- 拥抱开源, Office 365开发迎来新时代
这个话题我曾经写过文章,也在一些场合做过专题分享.今天换一种方式,你可以直接点击下面这个小程序,用十分钟左右的时间,听我再讲一讲吧. 你需要在微信里面才能看到下面的小程序链接,并且可以直接点击 你可以 ...
- 微软正在用实际行动告诉你: 拥抱开源,微软是认真的
2017年4月19日至20日,由工业和信息化部指导.中国信息通信研究院主办.云计算开源产业联盟承办的"全球云计算开源峰会"在国家会议中心举行.微软.NET CORE开发平台荣获由峰 ...
最新文章
- SliverLight注册字典转换器方法
- 一次毕生难忘的 Java 内存泄漏排查经历
- 读书笔记_Effective_C++_条款三十一:将文件间的编译依存关系降至最低(第二部分)...
- 查md5或者sha1值
- 迁移到php7,迁移PHP版本到PHP7
- nagios学习笔记(二)
- 卖萌屋福利场:《机器阅读理解》免费送送送!
- 解决the resource is not on the build path of a java project
- linux四剑客-grep/find/sed/awk/详解-技术流ken
- 猫和老鼠服务器维护多久结束,猫和老鼠手游关服公告 告别是为了每次更好的遇见!...
- Linus 07年在 Google讲座介绍Git的特点和设计思路
- 题目1140:八皇后
- 在aarch64-himix100-linux-gcc下cmake报错(The C compiler identification is unknown)
- 自动驾驶_感知_目标检测(基于图像)
- 科研神器----数据提取软件WebPlotDigitizer的使用
- Shopee跨境电商开店高频问题解答
- 4.2.5 求解幂集问题
- 搭建OA系统运维需要了解的知识?
- 免费得到高程地图的方法
- Win10彻底删除Windows.old文件夹
热门文章
- 快速搭建实验环境:使用 Terraform 部署 Proxmox 虚拟机
- 存储基础:磁盘 IO 为什么总叫你对齐?
- 近7万新冠域名一半是钓鱼网站?以色列老牌安全厂商Check Point推出全端保护新战略
- VMware为全球数字化基础架构提供原生安全
- 详解云计算、大数据和人工智能的区别与联系
- php 动态 控件,PHP技术在动态网页表单控件提取中的应用研究
- 前台传String日期格式后台用Date类型接收
- Springboot2.x +JPA 集成 Apache ShardingSphere 同库分表
- 更改默认软件下载的路径
- CentOS7.4下载与安装