JPA 一對多延遲加載與關係維護

JPA一對多延遲加載(orders和orderdetails), 對於一次查詢大量數據和多線程併發非常有幫助。

1. 一對多一般默認就是延遲加載, 在用到具體屬性的時候纔會執行SQL去抓取數據。

entity.getItems(); //不執行sql
entity.getItems().getProperty(); // 具體使用的纔會執行sql

   1.1 多對一默認是關閉懶加載的, 需要註解顯示開啓懶加載

2. 屬性級延遲加載註解(就算是blob等大字段JPA好像也不支持, 可以單獨設置爲一個實體, 然後做OneToOne懶加載)

@Basic(fetch = FetchType.Lazy)

    package cn.itcast.bean;   
      
    import java.util.HashSet;   
    import java.util.Set;   
      
    import javax.persistence.CascadeType;   
    import javax.persistence.Column;   
    import javax.persistence.Entity;   
    import javax.persistence.FetchType;   
    import javax.persistence.GeneratedValue;   
    import javax.persistence.Id;   
    import javax.persistence.OneToMany;   
    import javax.persistence.Table;   
      
    @Entity  
    @Table(name="orders")   //把表名改成orders(默認表名是order),防止默認表名order與數據庫的關鍵字"order by"中的order衝突。不改的話測試不成功,出現異常,orderitem表建立成功,order表建不了。   
    public class Order {   
        private String orderId;   
        private Float amount = 0f;   
        private List<OrderDetail> orderDetails= new ArrayList<OrderDetail>();   
      
        @Id //要注意:目前JPA規範並沒有提供UUID這種生成策略,目前主鍵值只提供了整型的生成方式,所以@GeneratedValue這個註解就不能在這裏用上,不能對字符串進行id自增長。   
        @Column(length = 12)   
        public String getOrderId() {   
            return orderId;   
        }   
      
        public void setOrderId(String orderId) {   
            this.orderId = orderId;   
        }   
      
        @Column(nullable = false)   
        public Float getAmount() {   
            return amount;   
        }   
      
        public void setAmount(Float amount) {   
            this.amount = amount;   
        }   
      
        @OneToMany(cascade = { CascadeType.REFRESH, CascadeType.PERSIST,   
                CascadeType.MERGE, CascadeType.REMOVE },fetch=FetchType.LAZY,mappedBy="order")   
        //mappedBy="order",中的order是關係維護端的order屬性,這個order屬性的類型是這個bean。   
        public Set<OrderDetail> getOrderDetails() {   
            return orderDetails;   
        }   
        /*  
        @OneToMany(fetch=FetchType.)的選項有,如下圖:  
            FetchType.EAGER:代表立即加載;  
            FetchType.LAZY:代表延遲加載。  
                  
        當我們把fetch設置爲FetchType.LAZY的時候,什麼時候初始化items裏面的數據呢?當我們第一次訪問這個屬性,並對這個屬性進行操作的時候,這個集合的數據纔會從數據庫裏面load出來。但要注意:當我們訪問這個延遲屬性的時候,我們的前提要EntityManager這個對象沒有被關閉,如果被關閉了我們再去訪問延遲屬性的話,就訪問不到,並拋出延遲加載意外。  
        如果沒有設置fetch這屬性的話,會怎麼樣呢?是立即加載?還是延遲加載呢?  
        記住@OneToMany這個標籤最後的英文單詞,如果是要得到Many的一方,我不管你前面是什麼,只要後面的單詞是Many,也就是說要得到多的一方,你們就給我記住,默認的加載策略就是延遲加載(Many記錄可能上幾萬條,立即加載的話可能對效率影響大,所以延遲加載)。  
        反過來,如果後面是One呢?因爲它是加載一的一方,這對性能影響不是很大,所以它的默認加載策略是立即加載。  
          
        mappedBy:我們怎麼知道關係的維護端和被維護端呢?當然JPA規範規定多的一端應該是爲維護端(關係維護段增加一個字段爲外鍵,裏面保存的是一的一端的主鍵),一的一端爲關係被維護端,那麼我們總要在程序裏給他們打上標誌吧?雖然規範是這麼規定,但總要申明一下吧?就是通過mappedBy屬性,只要哪個類出現了mappedBy,那麼這個類就是關係的被維護端。裏面的值指定的是關係維護端。  
        orderDetail這邊由哪一個屬性去維護關係呢?是OrderItem類的order屬性。  
        mappedBy屬性對應Hibernate裏面的inverse屬性:<SET name="orderDetails" inverse="true"></SET>  
          
        */  
      
        public void setOrderDetails(List<OrderDetail> orderDetails) {   
            this.orderDetails<span style="font-family: Arial, Helvetica, sans-serif;"> </span>= orderDetails;   
        }   
      
        //用這個方法會方便很多   
        public void addOrderDetail(OrderDetail orderDetail){   
            orderDetail.setOrder(this);   //關係維護方orderDetail加入關係被維護方(this)後,才能維護更新關係(orderDetail表中的外鍵字段order_id),維護關係其實就是更新外鍵。只有爲關係維護端設置了關係被維護端,關係才能建立起來。   
            this.orderDetails.add(orderDetail);   
        }
        
        public void removeOrderDetail(OrderDetail orderDetail){
             orderDetail.setOrderDetail(null);
             this.orderDetails.remove(orderDetail);
        }


    package cn.itcast.bean;   
      
    import javax.persistence.CascadeType;   
    import javax.persistence.Column;   
    import javax.persistence.Entity;   
    import javax.persistence.GeneratedValue;   
    import javax.persistence.Id;   
    import javax.persistence.JoinColumn;   
    import javax.persistence.ManyToOne;   
      
    @Entity  
    public class OrderDetail {   
        private Integer id;   
        private String productName;   
        private Float sellPrice = 0f;   //默認值爲0。   
        private Order order;   
      
        @Id  
        @GeneratedValue  //id自增長方式生成主鍵。   
        public Integer getId() {   
            return id;   
        }   
      
        public void setId(Integer id) {   
            this.id = id;   
        }   
      
        @Column(length = 40, nullable = false)   
        public String getProductName() {   
            return productName;   
        }   
      
        public void setProductName(String productName) {   
            this.productName = productName;   
        }   
      
        @Column(nullable = false)   
        public Float getSellPrice() {   
            return sellPrice;   
        }   
      
        public void setSellPrice(Float sellPrice) {   
            this.sellPrice = sellPrice;   
        }   
      
        @ManyToOne(cascade={CascadeType.MERGE,CascadeType.REFRESH},optional=false)   
        @JoinColumn(name="order_id")   //設置外鍵的名稱。   
        public Order getOrder() {   //OrderItem是關係維護端,負責關係更新,它是根據它的order屬性值維護關係的。當它保存的時候(主動保存或是被級聯保存),他會根據order屬性的值更新關係,當order爲null時,就不會更新關係了。級聯操作也是根據雙方對象中的映射屬性值進行的,當映射屬性沒值的時候就不會對對方進行級聯操作了。   
            return order;   
        }   
        /*  
        @ManyToOne的級聯保存(CascadeType.PERSIST)是不需要的,不可能說你保存某個訂單項OrderItem的時候,也保存訂單Order的。通常都是保存訂單Order的時候,保存訂單項OrderItem的。  
        CascadeType.MERGE:如果我們更新了訂單項orderItem產品的價錢,那麼整個訂單Order的總金額是會發生改變的,所以可以定義這個級聯更新。  
        CascadeType.REFRESH:如果我們想得到目前數據庫裏orderItem最新的數據的話,我們也希望得到訂單order的最新數據,我們可以定義這個級聯刷新,就是說把數據庫裏最新的數據重新得到。  
        CascadeType.REMOVE:這個屬性這裏肯定不設。就好比現在有一個訂單,一個訂單裏面有3個購物項orderItem,買了A,B,C三個產品,我現在不要A這個產品了,我們只是把A這條記錄刪掉,那麼如果這裏定義了級聯刪除的話,那麼你刪除A記錄的同時,也會把整個訂單也刪除掉,所以這裏不需要設級聯刪除。  
        */  
        //optional:說明order這個是否是可選的?是否可以沒有的?false表示必須的,true表示是可選的。   
      
        public void setOrder(Order order) {   
            this.order = order;   
        }   
    }   



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章