JPA 2.1实体图–第1部分:命名实体图
延遲加載通常是JPA 2.0的問題。 如果要使用FetchType.LAZY(默認(rèn))或FetchType.EAGER來加載關(guān)系,則必須在實(shí)體上進(jìn)行定義,并且始終使用此模式。 僅當(dāng)我們要始終加載關(guān)系時才使用FetchType.EAGER。 FetchType.LAZY幾乎在所有情況下都用于獲得性能良好且可伸縮的應(yīng)用程序。
但這并非沒有缺點(diǎn)。 如果必須使用關(guān)系的元素,則需要確保在從數(shù)據(jù)庫加載實(shí)體的事務(wù)中初始化該關(guān)系。 這可以通過使用特定的查詢來完成,該查詢從數(shù)據(jù)庫中讀取實(shí)體和所需的關(guān)系。 但這將導(dǎo)致用例特定的查詢。 另一個選擇是在您的業(yè)務(wù)代碼中訪問該關(guān)系,這將導(dǎo)致對每個關(guān)系的附加查詢。 兩種方法都不完美。
JPA 2.1實(shí)體圖是一個更好的解決方案。 實(shí)體圖的定義與查詢無關(guān),并且定義了要從數(shù)據(jù)庫中獲取哪些屬性。 實(shí)體圖可以用作訪存圖或負(fù)載圖。 如果使用提取圖,則僅由實(shí)體圖指定的屬性將被視為FetchType.EAGER。 所有其他屬性將是惰性的。 如果使用負(fù)載圖,則實(shí)體圖未指定的所有屬性將保留其默認(rèn)提取類型。
讓我們看看如何定義和使用實(shí)體圖。
示例實(shí)體
在此示例中,我們將使用帶有項目列表的訂單,每個項目都有一個產(chǎn)品。 所有關(guān)系都是懶惰的。
訂單實(shí)體:
@Entity @Table(name = "purchaseOrder") @NamedEntityGraph(name = "graph.Order.items", attributeNodes = @NamedAttributeNode(value = "items", subgraph = "items"), subgraphs = @NamedSubgraph(name = "items", attributeNodes = @NamedAttributeNode("product"))) public class Order implements Serializable {@Id@GeneratedValue(strategy = GenerationType.AUTO)@Column(name = "id", updatable = false, nullable = false)private Long id = null;@Version@Column(name = "version")private int version = 0;@Columnprivate String orderNumber;@OneToMany(mappedBy = "order", fetch = FetchType.LAZY)private Set<OrderItem> items = new HashSet<OrderItem>();...OrderItem實(shí)體:
@Entity public class OrderItem implements Serializable {@Id@GeneratedValue(strategy = GenerationType.AUTO)@Column(name = "id", updatable = false, nullable = false)private Long id = null;@Version@Column(name = "version")private int version = 0;@Columnprivate int quantity;@ManyToOneprivate Order order;@ManyToOne(fetch = FetchType.LAZY)private Product product;產(chǎn)品實(shí)體:
@Entity public class Product implements Serializable {@Id@GeneratedValue(strategy = GenerationType.AUTO)@Column(name = "id", updatable = false, nullable = false)private Long id = null;@Version@Column(name = "version")private int version = 0;@Columnprivate String name;命名實(shí)體圖
命名實(shí)體圖的定義是通過實(shí)體上的@NamedEntityGraph批注完成的。 它定義了唯一的名稱和已加載的屬性列表( attributeNodes )。
以下示例顯示了實(shí)體圖“ graph.Order.items”的定義,該圖將加載Order的OrderItem列表。
@Entity @Table(name = "purchase_order") @NamedEntityGraph(name = "graph.Order.items", attributeNodes = @NamedAttributeNode("items")) public class Order implements Serializable {...現(xiàn)在我們已經(jīng)定義了實(shí)體圖,我們可以在查詢中使用它。 因此,我們需要創(chuàng)建一個具有查詢提示的Map,并將其設(shè)置為find或query方法調(diào)用上的附加參數(shù)。
以下代碼段顯示了如何在find語句中使用命名實(shí)體圖作為獲取圖。
EntityGraph graph = this.em.getEntityGraph("graph.Order.items");Map hints = new HashMap(); hints.put("javax.persistence.fetchgraph", graph);return this.em.find(Order.class, orderId, hints);命名子圖
我們使用實(shí)體圖來定義Order實(shí)體的提取操作。 如果我們想對OrderItem實(shí)體執(zhí)行相同的操作,則可以使用實(shí)體子圖執(zhí)行此操作。 命名子圖的定義類似于命名實(shí)體圖的定義,并且可以引用為attributeNode。
以下代碼段顯示了用于加載每個OrderItem的Product的子圖的定義。 定義的實(shí)體圖將獲取包含所有OrderItem及其產(chǎn)品的Order 。
@Entity @Table(name = "purchase_order") @NamedEntityGraph(name = "graph.Order.items", attributeNodes = @NamedAttributeNode(value = "items", subgraph = "items"), subgraphs = @NamedSubgraph(name = "items", attributeNodes = @NamedAttributeNode("product"))) public class Order implements Serializable {里面發(fā)生什么事了?
好的,從發(fā)展的角度來看,實(shí)體圖很棒。 它們易于使用,我們不需要編寫其他代碼來避免延遲加載問題。 但是里面發(fā)生了什么? 有多少查詢發(fā)送到數(shù)據(jù)庫? 讓我們看看休眠調(diào)試日志。
2014-03-22 21:56:08,285 DEBUG [org.hibernate.loader.plan.build.spi.LoadPlanTreePrinter] (pool-2-thread-1) LoadPlan(entity=blog.thoughts.on.java.jpa21.entity.graph.model.Order) - Returns - EntityReturnImpl(entity=blog.thoughts.on.java.jpa21.entity.graph.model.Order, querySpaceUid=<gen:0>, path=blog.thoughts.on.java.jpa21.entity.graph.model.Order) - CollectionAttributeFetchImpl(collection=blog.thoughts.on.java.jpa21.entity.graph.model.Order.items, querySpaceUid=<gen:1>, path=blog.thoughts.on.java.jpa21.entity.graph.model.Order.items) - (collection element) CollectionFetchableElementEntityGraph(entity=blog.thoughts.on.java.jpa21.entity.graph.model.OrderItem, querySpaceUid=<gen:2>, path=blog.thoughts.on.java.jpa21.entity.graph.model.Order.items.<elements>) - EntityAttributeFetchImpl(entity=blog.thoughts.on.java.jpa21.entity.graph.model.Product, querySpaceUid=<gen:3>, path=blog.thoughts.on.java.jpa21.entity.graph.model.Order.items.<elements>.product) - QuerySpaces - EntityQuerySpaceImpl(uid=<gen:0>, entity=blog.thoughts.on.java.jpa21.entity.graph.model.Order) - SQL table alias mapping - order0_ - alias suffix - 0_ - suffixed key columns - {id1_2_0_} - JOIN (JoinDefinedByMetadata(items)) : <gen:0> -> <gen:1> - CollectionQuerySpaceImpl(uid=<gen:1>, collection=blog.thoughts.on.java.jpa21.entity.graph.model.Order.items) - SQL table alias mapping - items1_ - alias suffix - 1_ - suffixed key columns - {order_id4_2_1_} - entity-element alias suffix - 2_ - 2_entity-element suffixed key columns - id1_0_2_ - JOIN (JoinDefinedByMetadata(elements)) : <gen:1> -> <gen:2> - EntityQuerySpaceImpl(uid=<gen:2>, entity=blog.thoughts.on.java.jpa21.entity.graph.model.OrderItem) - SQL table alias mapping - items1_ - alias suffix - 2_ - suffixed key columns - {id1_0_2_} - JOIN (JoinDefinedByMetadata(product)) : <gen:2> -> <gen:3> - EntityQuerySpaceImpl(uid=<gen:3>, entity=blog.thoughts.on.java.jpa21.entity.graph.model.Product) - SQL table alias mapping - product2_ - alias suffix - 3_ - suffixed key columns - {id1_1_3_} 2014-03-22 21:56:08,285 DEBUG [org.hibernate.loader.entity.plan.EntityLoader] (pool-2-thread-1) Static select for entity blog.thoughts.on.java.jpa21.entity.graph.model.Order [NONE:-1]: select order0_.id as id1_2_0_, order0_.orderNumber as orderNum2_2_0_, order0_.version as version3_2_0_, items1_.order_id as order_id4_2_1_, items1_.id as id1_0_1_, items1_.id as id1_0_2_, items1_.order_id as order_id4_0_2_, items1_.product_id as product_5_0_2_, items1_.quantity as quantity2_0_2_, items1_.version as version3_0_2_, product2_.id as id1_1_3_, product2_.name as name2_1_3_, product2_.version as version3_1_3_ from purchase_order order0_ left outer join OrderItem items1_ on order0_.id=items1_.order_id left outer join Product product2_ on items1_.product_id=product2_.id where order0_.id=?日志顯示僅創(chuàng)建了一個查詢。 Hibernate使用實(shí)體圖來創(chuàng)建具有所有3個實(shí)體( Order , OrderItem和Product )的加載計劃,并通過一個查詢加載它們。
結(jié)論
我們定義了一個實(shí)體圖,該圖告訴實(shí)體管理器從數(shù)據(jù)庫中獲取3個相關(guān)實(shí)體的圖( Order , OrderItem和Product )。 實(shí)體圖的定義和用法與查詢無關(guān),并且僅產(chǎn)生一條select語句。 因此,解決了JPA 2.0方法的主要缺點(diǎn)(在開頭提到)。
從我的角度來看,新的實(shí)體圖功能確實(shí)很棒,并且可以解決延遲加載問題。 你怎么看待這件事?
翻譯自: https://www.javacodegeeks.com/2014/05/jpa-2-1-entity-graph-part-1-named-entity-graphs.html
總結(jié)
以上是生活随笔為你收集整理的JPA 2.1实体图–第1部分:命名实体图的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 为Lucene选择快速唯一标识符(UUI
- 下一篇: 常见的DDos攻击(ssr ddos攻击