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

相关文章
相关标签/搜索