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 实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何理解android的函数,通过And
- 下一篇: python不能保存中文_Python