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

原文章地址:http://hai0378.iteye.com/blog/1558397
Java代碼   收藏代碼
  1. package cn.itcast.bean;     
  2.     
  3. import java.util.HashSet;     
  4. import java.util.Set;     
  5.     
  6. import javax.persistence.CascadeType;     
  7. import javax.persistence.Column;     
  8. import javax.persistence.Entity;     
  9. import javax.persistence.FetchType;     
  10. import javax.persistence.GeneratedValue;     
  11. import javax.persistence.Id;     
  12. import javax.persistence.OneToMany;     
  13. import javax.persistence.Table;     
  14.     
  15. @Entity    
  16. @Table(name="orders")   //把表名改爲orders(默認表名是order),防止默認表名order與數據庫的關鍵字"order by"中的order衝突。不改的話測試不成功,出現異常,orderitem表創建成功,order表建不了。     
  17. public class Order {     
  18.     private String orderId;     
  19.     private Float amount = 0f;     
  20.     private Set<OrderItem> items = new HashSet<OrderItem>();     
  21.     
  22.     @Id //要注意:目前JPA規範並無提供UUID這種生成策略,目前主鍵值只提供了整型的生成方式,因此@GeneratedValue這個註解就不能在這裏用上,不能對字符串進行id自增加。     
  23.     @Column(length = 12)     
  24.     public String getOrderId() {     
  25.         return orderId;     
  26.     }     
  27.     
  28.     public void setOrderId(String orderId) {     
  29.         this.orderId = orderId;     
  30.     }     
  31.     
  32.     @Column(nullable = false)     
  33.     public Float getAmount() {     
  34.         return amount;     
  35.     }     
  36.     
  37.     public void setAmount(Float amount) {     
  38.         this.amount = amount;     
  39.     }     
  40.     
  41.     @OneToMany(cascade = { CascadeType.REFRESH, CascadeType.PERSIST,     
  42.             CascadeType.MERGE, CascadeType.REMOVE },fetch=FetchType.LAZY,mappedBy="order")     
  43.     //mappedBy="order",中的order是關係維護端的order屬性,這個order屬性的類型是這個bean。     
  44.     public Set<OrderItem> getItems() {     
  45.         return items;     
  46.     }     
  47.     /*   
  48.     @OneToMany(fetch=FetchType.)的選項有,以下圖:   
  49.         FetchType.EAGER:表明當即加載;   
  50.         FetchType.LAZY:表明延遲加載。   
  51.                
  52.     當咱們把fetch設置爲FetchType.LAZY的時候,何時初始化items裏面的數據呢?當咱們第一次訪問這個屬性,並對這個屬性進行操做的時候,這個集合的數據纔會從數據庫裏面load出來。但要注意:當咱們訪問這個延遲屬性的時候,咱們的前提要EntityManager這個對象沒有被關閉,若是被關閉了咱們再去訪問延遲屬性的話,就訪問不到,並拋出延遲加載意外。   
  53.     若是沒有設置fetch這屬性的話,會怎麼樣呢?是當即加載?仍是延遲加載呢?   
  54.     記住@OneToMany這個標籤最後的英文單詞,若是是要獲得Many的一方,我無論你前面是什麼,只要後面的單詞是Many,也就是說要獲得多的一方,大家就給我記住,默認的加載策略就是延遲加載(Many記錄可能上幾萬條,當即加載的話可能對效率影響大,因此延遲加載)。   
  55.     反過來,若是後面是One呢?由於它是加載一的一方,這對性能影響不是很大,因此它的默認加載策略是當即加載。   
  56.        
  57.     mappedBy:咱們怎麼知道關係的維護端和被維護端呢?固然JPA規範規定多的一端應該是爲維護端(關係維護段增長一個字段爲外鍵,裏面保存的是一的一端的主鍵),一的一端爲關係被維護端,那麼咱們總要在程序裏給他們打上標誌吧?雖然規範是這麼規定,但總要申明一下吧?就是經過mappedBy屬性,只要哪一個類出現了mappedBy,那麼這個類就是關係的被維護端。裏面的值指定的是關係維護端。   
  58.     orderItem這邊由哪個屬性去維護關係呢?是OrderItem類的order屬性。   
  59.     mappedBy屬性對應Hibernate裏面的inverse屬性:<SET name="items" inverse="true"></SET>   
  60.        
  61.     */    
  62.     
  63.     public void setItems(Set<OrderItem> items) {     
  64.         this.items = items;     
  65.     }     
  66.     
  67.     //用這個方法會方便不少     
  68.     public void addOrderItem(OrderItem orderItem){     
  69.         orderItem.setOrder(this);   //關係維護方orderItem加入關係被維護方(this)後,才能維護更新關係(orderItem表中的外鍵字段order_id),維護關係其實就是更新外鍵。只有爲關係維護端設置了關係被維護端,關係才能創建起來。     
  70.         this.items.add(orderItem);     
  71.     }     
  72. }     

 


OrderItem.javajava

Java代碼   收藏代碼
  1. package cn.itcast.bean;     
  2.     
  3. import javax.persistence.CascadeType;     
  4. import javax.persistence.Column;     
  5. import javax.persistence.Entity;     
  6. import javax.persistence.GeneratedValue;     
  7. import javax.persistence.Id;     
  8. import javax.persistence.JoinColumn;     
  9. import javax.persistence.ManyToOne;     
  10.     
  11. @Entity    
  12. public class OrderItem {     
  13.     private Integer id;     
  14.     private String productName;     
  15.     private Float sellPrice = 0f;   //默認值爲0。     
  16.     private Order order;     
  17.     
  18.     @Id    
  19.     @GeneratedValue  //id自增加方式生成主鍵。     
  20.     public Integer getId() {     
  21.         return id;     
  22.     }     
  23.     
  24.     public void setId(Integer id) {     
  25.         this.id = id;     
  26.     }     
  27.     
  28.     @Column(length = 40, nullable = false)     
  29.     public String getProductName() {     
  30.         return productName;     
  31.     }     
  32.     
  33.     public void setProductName(String productName) {     
  34.         this.productName = productName;     
  35.     }     
  36.     
  37.     @Column(nullable = false)     
  38.     public Float getSellPrice() {     
  39.         return sellPrice;     
  40.     }     
  41.     
  42.     public void setSellPrice(Float sellPrice) {     
  43.         this.sellPrice = sellPrice;     
  44.     }     
  45.     
  46.     @ManyToOne(cascade={CascadeType.MERGE,CascadeType.REFRESH},optional=false)     
  47.     @JoinColumn(name="order_id")   //設置外鍵的名稱。     
  48.     public Order getOrder() {   //OrderItem是關係維護端,負責關係更新,它是根據它的order屬性值維護關係的。當它保存的時候(主動保存或是被級聯保存),他會根據order屬性的值更新關係,當order爲null時,就不會更新關係了。級聯操做也是根據雙方對象中的映射屬性值進行的,當映射屬性沒值的時候就不會對對方進行級聯操做了。     
  49.         return order;     
  50.     }     
  51.     /*   
  52.     @ManyToOne的級聯保存(CascadeType.PERSIST)是不須要的,不可能說你保存某個訂單項OrderItem的時候,也保存訂單Order的。一般都是保存訂單Order的時候,保存訂單項OrderItem的。   
  53.     CascadeType.MERGE:若是咱們更新了訂單項orderItem產品的價錢,那麼整個訂單Order的總金額是會發生改變的,因此能夠定義這個級聯更新。   
  54.     CascadeType.REFRESH:若是咱們想獲得目前數據庫裏orderItem最新的數據的話,咱們也但願獲得訂單order的最新數據,咱們能夠定義這個級聯刷新,就是說把數據庫裏最新的數據從新獲得。   
  55.     CascadeType.REMOVE:這個屬性這裏確定不設。就比如如今有一個訂單,一個訂單裏面有3個購物項orderItem,買了A,B,C三個產品,我如今不要A這個產品了,咱們只是把A這條記錄刪掉,那麼若是這裏定義了級聯刪除的話,那麼你刪除A記錄的同時,也會把整個訂單也刪除掉,因此這裏不須要設級聯刪除。   
  56.     */    
  57.     //optional:說明order這個是不是可選的?是否能夠沒有的?false表示必須的,true表示是可選的。     
  58.     
  59.     public void setOrder(Order order) {     
  60.         this.order = order;     
  61.     }     
  62. }     

 

OneToManyTest.java數據庫

Java代碼   收藏代碼
  1. package junit.test;     
  2.     
  3. import javax.persistence.EntityManager;     
  4. import javax.persistence.EntityManagerFactory;     
  5. import javax.persistence.Persistence;     
  6.     
  7. import org.junit.BeforeClass;     
  8. import org.junit.Test;     
  9.     
  10. import cn.itcast.bean.Order;     
  11. import cn.itcast.bean.OrderItem;     
  12.     
  13. public class OneToManyTest {     
  14.     
  15.     @BeforeClass    
  16.     public static void setUpBeforeClass() throws Exception {     
  17.     }     
  18.     
  19.     @Test    
  20.     public void save() {     
  21.         EntityManagerFactory factory = Persistence.createEntityManagerFactory("itcast");     
  22.         EntityManager em = factory.createEntityManager();     
  23.         em.getTransaction().begin();     
  24.     
  25.         Order order = new Order();     
  26.         order.setAmount(34f);     
  27.         order.setOrderId("992");  //orderId是數據庫裏面的主鍵,同時也是實體的標識。這裏並無使用Id自增加的方式來生成主鍵值,而是本身設值,因此能夠隨便寫。若是想用UUID,能夠這樣寫UUID.randomUUID().toString();這個類JDK5提供了。     
  28.         OrderItem orderItem1 = new OrderItem();     
  29.         orderItem1.setProductName("排球");     
  30.         orderItem1.setSellPrice(90f);     
  31.         OrderItem orderItem2=new OrderItem();     
  32.         orderItem2.setProductName("籃球");     
  33.         orderItem2.setSellPrice(30f);     
  34.         order.addOrderItem(orderItem1);     
  35.         order.addOrderItem(orderItem2);     
  36.     
  37.         em.persist(order);     
  38.         em.getTransaction().commit();     
  39.         em.close();     
  40.         factory.close();     
  41.     }     
  42.     
  43. }     

 

 

運行junit測試,發現保存訂單Order的時候,也保存了訂單項OrderItem.爲何呢?是由於訂單Order和訂單項OrderItem定義 了級聯保存(CascadeType.PERSIST)關係,這個級聯關係在咱們調用em.persist(order);的persist方法時就會起 做用。app

相關文章
相關標籤/搜索