語境
我們的PUT端點基本上UPSERT通過首先呼叫DELETE所有物體,然后呼叫INSERT INTO.
但是,在除錯時,我看到UPDATEJPA 也發出了一些呼叫,出于性能原因,我試圖避免這種情況。我希望只有 2 個INSERT呼叫:一個用于Parent,一個用于所有Child.
這似乎只發生在@OneToMany物體上。
如果它可以提供幫助,我們使用 EclipseLink 作為我們的 JPA 提供程式,并被batch-writing激活。該應用程式是使用 Spring Data 構建的。
模型
@Entity
@Table
@Data // org.lombok
@IdClass(ParentPrimaryKey.class)
public class Parent {
@Id
@Column(name = "product", updatable = false)
private String product;
@Id
@Column(name = "source", updatable = false)
private String source;
@Column
private String whatever;
@OneToMany(cascade = {CascadeType.ALL}, orphanRemoval = true)
@JoinColumns({
@JoinColumn(name = "product", referencedColumnName = "product"),
@JoinColumn(name = "source", referencedColumnName = "source")
})
private List<Child> details;
}
@Entity
@Table
@Data // org.lombok
@IdClass(ChildPrimaryKey.class)
public class Child {
@Id
@Column(name = "product", updatable = false)
private String product;
@Id
@Column(name = "source", updatable = false)
private String source;
@Id
@Column(name = "extra", updatable = false)
private String extra;
@Column
private String foo;
@Column
private String bar;
}
關聯的當前日志
INSERT INTO PARENT (product, source, whatever) VALUES (?, ?, ?)
bind => [A, A, A]
bind => [B, B, A]
INSERT INTO CHILD (product, source, extra, foo, bar) VALUES (?, ?, ?, ?, ?)
bind => [A, A, 1, B, B]
bind => [A, A, 2, C, C]
bind => [A, A, 3, D, D]
bind => [B, B, 1, B, B]
bind => [B, B, 2, C, C]
bind => [B, B, 3, D, D]
UPDATE CHILD SET product = ?, source = ? WHERE ((product = ?) AND (source = ?) AND (extra = ?))
bind => [A, A, A, A, 1]
bind => [A, A, A, A, 2]
bind => [A, A, A, A, 3]
bind => [B, B, B, B, 1]
bind => [B, B, B, B, 2]
bind => [B, B, B, B, 3]
嘗試修復
基于此答案,我嘗試添加nullable=false:
public class Child {
@Id
@Column(name = "product", updatable = false, nullable = false)
private String product;
@Id
@Column(name = "source", updatable = false, nullable = false)
private String source;
@Id
@Column(name = "extra", updatable = false, nullable = false)
private String extra;
// the rest is identical...
}
結果日志
As can be seen, this indeed removes the UPDATE call, but it increases the amount of total queries that will be issued to our DB, and thus means the performance will actually be worse (it will go from a total of 3 requests, to 2N):
INSERT INTO PARENT (product, source, whatever) VALUES (?, ?, ?)
bind => [A, A, A]
INSERT INTO CHILD (product, source, extra, foo, bar) VALUES (?, ?, ?, ?, ?)
bind => [A, A, 1, B, B]
bind => [A, A, 2, C, C]
bind => [A, A, 3, D, D]
INSERT INTO PARENT (product, source, whatever) VALUES (?, ?, ?)
bind => [B, B, A]
INSERT INTO CHILD (product, source, extra, foo, bar) VALUES (?, ?, ?, ?, ?)
bind => [B, B, 1, B, B]
bind => [B, B, 2, C, C]
bind => [B, B, 3, D, D]
uj5u.com熱心網友回復:
兩種可能更適合您的選項。
第一個選項
保持其他一切不變:
@Entity
@Table
@Data // org.lombok
@IdClass(ParentPrimaryKey.class)
public class Parent {
@Id
@Column(name = "product", updatable = false)
private String product;
@Id
@Column(name = "source", updatable = false)
private String source;
@Column
private String whatever;
@OneToMany(cascade = {CascadeType.ALL}, orphanRemoval = true)
@JoinColumns({
@JoinColumn(name = "product", referencedColumnName = "product", insertable = false, updatable = false),
@JoinColumn(name = "source", referencedColumnName = "source", insertable = false, updatable = false)
})
private List<Child> details;
}
這將確保 Child 表中的外鍵僅由它們各自的 @Id 映射控制。
第二種選擇
或者,您可以反過來,讓 JPA 使用派生 ID 完全為您設定子物體實體中的值:
@Entity
@IdClass(ChildPrimaryKey.class)
public class Child {
@Id
@JoinColumns({
@JoinColumn(name = "product", referencedColumnName = "product"),
@JoinColumn(name = "source", referencedColumnName = "source")
})
Parent parent;
@Id
@Column(name = "extra")
private String extra;
// the rest is identical...
}
public class ChildPrimaryKey {
ParentPrimaryKey parent;
String extra;
}
這將確保根據父實體的值在子表中設定源和產品列。Parent 的詳細資訊映射然后可以洗掉連接列定義,并宣告它是由 Child 的父關系映射的:
@OneToMany(mappedBy = "parent",cascade = {CascadeType.ALL}, orphanRemoval = true)
private List<Child> details;
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/366954.html
標籤:spring-boot jpa spring-data-jpa spring-data eclipselink
