Hibernate一对多(双向)及多对多

  • Hibernate:  
  •     ///  
  •     双向关联就是有“一对多”和“多对一”两个关联组合而成德,在双向关联的两端都知道对方是谁。  
  •   
  •     下面就开始演示这种关联。  
  •   
  •     首先定义我们需要使用的POJO对象。  
  •   
  •     public class Member  
  •     {  
  •         private String id;   
  •         private String name;   
  •         private Integer age;   
  •         private Set<Order> orders = new HashSet<Order>();//我知道Order对象  
  •         ……  
  •     }  
  •   
  •     public class Order  
  •     {  
  •         private Integer id;   
  •         private String name;   
  •         private String num;   
  •         private Member member;//我知道Member对象  
  •         ……  
  •     }  
  •   
  •     两个POJO对应的映射文件分别为Member.hbm.xml和Order.hbm.xml。  
  •   
  •     Member.hbm.xml  
  •   
  •     <hibernate-mapping package="org.louis.domain">   
  •         <class name="Member" table="TEST_MEMBER">  
  •             <id name="id" column="ID">   
  •                 <generator class="uuid.hex"></generator>   
  •             </id>   
  •             <property name="age" column="AGE"></property>   
  •             <property name="name" column="NAME"></property>   
  •             <set name="orders" cascade="all" inverse="true">  
  •                 <!--设置inverse=”true”表示Member不在作为主控方,就是说不再由Member来维持关联关系,  
  •                 而有Order方来维持关联关系,这样Order在持久化的时候会主动去获取Member的主键值来作为自己  
  •                 的外键值。 在one-to-manay关联关系中,一般将manay端设置为主控方(inverse=”false”),  
  •                 这样将有助于改善性能。默认情况下inverse=”false” -->   
  •                 <key column="MEMBER_ID"></key>   
  •                 <one-to-many class="Order"/>   
  •             </set>  
  •         </class>   
  •     </hibernate-mapping>  
  •   
  •     Order.hbm.xml  
  •   
  •     <hibernate-mapping package="org.louis.domain">   
  •         <class name="Order" table="TEST_ORDER">   
  •             <id name="id" column="ID">   
  •                 <generator class="native"></generator>   
  •             </id>   
  •             <property name="name" column="NAME"></property>   
  •             <property name="num" column="NUM"></property>   
  •             <many-to-one name="member" class="Member" column="MEMBER_ID"></many-to-one>  
  •     </hibernate-mapping>  
  •   
  •     下面我们来进行测试。  
  •   
  •     a、插入数据  
  •   
  •     public void insert()  
  •     {   
  •         Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession();   
  •         session.beginTransaction();   
  •         Member m = new Member();   
  •         m.setAge(24);   
  •         m.setName("Louis");  
  •   
  •         Order order = new Order();  
  •         order.setName("order 1");  
  •         order.setNum("order num 1");  
  •         order.setMember(m);  
  •         m.getOrders().add(order);  
  •   
  •         session.save(m);   
  •         session.getTransaction().commit();   
  •     }  
  •   
  •     查看Hibernate在后台使用的SQL语句如下:  
  •   
  •     Hibernate:   
  •         insert   
  •         into   
  •             TEST_MEMBER   
  •             (AGE, NAME, ID)   
  •         values   
  •             (?, ?, ?)   
  •     Hibernate:   
  •         insert   
  •         into   
  •             TEST_ORDER   
  •             (NAME, NUM, MEMBER_ID)   
  •         values   
  •             (?, ?, ?)  
  •   
  •     仅仅就两条语句,明显比单向关联的时候少了一条更新语句(把Order的外键进行更新为Menber的主键值)。  
  •   
  •     b、加载数据  
  •       
  •     和单向关联的区别在于,如果加载的是Order对象,那么它也知道和它关联的对象。  
  •   
  •     c、删除数据  
  •       
  •     删除数据和单向关联时的删除数据的区别在于,对Member及它的关联对象Order加载后,不需要在更新Order的外键为NULL,而是紧跟着逐条删除Order,最后删除Member。
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  • ///  
  • Hibernate:  
  •     ///  
  •     多对多关联是Hibernate中一种比较特殊的关联,它需要借助中间表来完成多对多信息的保存。多对多关联只有双向关联。  
  •   
  •     对于一个订单(Order)可以包含多种产品(Products),而对于每种产品可以存在于多个订单之中,是一个典型的多对多关系。  
  •   
  •     本次演示用到的两个POJO类如下:  
  •   
  •     public class Order  
  •     {  
  •         private Integer id;  
  •         private String name;  
  •         private String num;  
  •         private Set<Product> products = new HashSet<Product>();//  
  •         ......  
  •     }  
  •   
  •     public class Product  
  •     {  
  •         private Integer id;  
  •         private String name;  
  •         private Set<Order> orders = new HashSet<Order>();//  
  •         ......  
  •     }  
  •   
  •     它们对应的映射文件分别为:  
  •   
  •     Order.hbm.xml  
  •   
  •     <hibernate-mapping package="org.louis.domain">  
  •         <class name="Order" table="TEST_ORDER">  
  •             <id name="id" column="ID">  
  •                 <generator class="native"></generator>  
  •             </id>  
  •               
  •             <property name="name" column="NAME"></property>  
  •             <property name="num" column="NUM"></property>  
  •               
  •             <set name="products" table="TEST_ORDER_PRODUCT" cascade="save-update" fetch="join">  
  •                 <key column="ORDER_ID"></key>  
  •                 <many-to-many class="Product" column="PRODUCT_ID"></many-to-many>  
  •             </set>  
  •         </class>  
  •     </hibernate-mapping>     
  •   
  •   
  •     Product.hbm.xml  
  •   
  •     <hibernate-mapping package="org.louis.domain">  
  •         <class name="Product" table="TEST_PRODUCT">  
  •             <id name="id" column="ID">  
  •                 <generator class="native"></generator>  
  •             </id>  
  •               
  •             <property name="name" column="NAME"></property>  
  •               
  •             <set name="orders" table="TEST_ORDER_PRODUCT" cascade="save-update" fetch="join">  
  •                 <key column="PRODUCT_ID"></key>  
  •                 <many-to-many class="Order" column="ORDER_ID"></many-to-many>  
  •             </set>  
  •         </class>  
  •     </hibernate-mapping>    
  •   
  •     我们注意到,在两个文件中都有<set>节点,同时都指定了其table属性,这是两个对象的的中间表,在多对多关联中,  
  •     很多操作都是通过的中间表来完成的;<set>元素的子元素<key>指定了中间表中的外键,它对应于当前文件的对象的  
  •     主键,如Order.hbm.xml中,对应于Order的主键;<many-to-many>指定了关联的另一方和中间表的对应于另一方主键  
  •     的外键。  
  •   
  •   
  •     下面来做一些测试。  
  •   
  •     a、插入数据  
  •   
  •         public void insert()  
  •         {  
  •             Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession();  
  •             session.beginTransaction();  
  •             Product p1 = new Product();  
  •             p1.setName("p1");  
  •             Product p2 = new Product();  
  •             p2.setName("p2");  
  •             Order order = (Order)session.load(Order.class, 3);  
  •     //      order.getProducts().add(p1);  
  •     //      order.getProducts().add(p2);  
  •             p1.getOrders().add(order);  
  •             p2.getOrders().add(order);  
  •             session.save(p1);  
  •             session.save(p2);  
  •             session.getTransaction().commit();  
  •         }  
  •   
  •         查看Hibernate在后台执行的SQL语句如下:  
  •   
  •         Hibernate:   
  •             select  
  •                 order0_.ID as ID6_1_,  
  •                 order0_.NAME as NAME6_1_,  
  •                 order0_.NUM as NUM6_1_,  
  •                 order0_.MEMBER_ID as MEMBER4_6_1_,  
  •                 products1_.ORDER_ID as ORDER1_3_,  
  •                 product2_.ID as PRODUCT2_3_,  
  •                 product2_.ID as ID8_0_,  
  •                 product2_.NAME as NAME8_0_   
  •             from  
  •                 TEST_ORDER order0_   
  •             left outer join  
  •                 TEST_ORDER_PRODUCT products1_   
  •                     on order0_.ID=products1_.ORDER_ID   
  •             left outer join  
  •                 TEST_PRODUCT product2_   
  •                     on products1_.PRODUCT_ID=product2_.ID   
  •             where  
  •                 order0_.ID=?  
  •         Hibernate:   
  •             insert   
  •             into  
  •                 TEST_PRODUCT  
  •                 (NAME)   
  •             values  
  •                 (?)  
  •         Hibernate:   
  •             insert   
  •             into  
  •                 TEST_PRODUCT  
  •                 (NAME)   
  •             values  
  •                 (?)  
  •         Hibernate:   
  •             insert   
  •             into  
  •                 TEST_ORDER_PRODUCT  
  •                 (PRODUCT_ID, ORDER_ID)   
  •             values  
  •                 (?, ?)  
  •         Hibernate:   
  •             insert   
  •             into  
  •                 TEST_ORDER_PRODUCT  
  •                 (PRODUCT_ID, ORDER_ID)   
  •             values  
  •                 (?, ?)  
  •           
  •         第一条是更加ID加载Order对象,同时将其关联对象也加载了。接着插入两个Product,然后用两条SQL语句向中间表里面插入反映关联关系的数据。  
  •   
  •         如果将Java代码修改为下面这样:  
  •   
  •         public void insert()  
  •         {  
  •             Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession();  
  •             session.beginTransaction();  
  •             Product p1 = new Product();  
  •             p1.setName("p1");  
  •             Product p2 = new Product();  
  •             p2.setName("p2");  
  •             Order order = (Order)session.load(Order.class, 3);  
  •             order.getProducts().add(p1);  
  •             order.getProducts().add(p2);  
  •             session.save(order);  
  •             session.getTransaction().commit();  
  •         }  
  •   
  •         我们发现Hibernate执行的SQL和上面的一样,由此看来,在这种多对多情况下,无论让谁来维护关系都是可以的,因为默认  
  •         情况下inverse="false";  
  •   
  •         我们再来看当设置Product.hbm.xml中的<set>节点属性inverse="true", 这表示对于两个对象的关联关系的维护有Order来做。  
  •   
  •         我们使用下面的代码来测试一下:  
  •   
  •         public void insert()  
  •         {  
  •             Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession();  
  •             session.beginTransaction();  
  •             Product p1 = new Product();  
  •             p1.setName("p1");  
  •             Product p2 = new Product();  
  •             p2.setName("p2");  
  •             Order order = (Order)session.load(Order.class, 3);  
  •     //      order.getProducts().add(p1);  
  •     //      order.getProducts().add(p2);  
  •             p1.getOrders().add(order);  
  •             p2.getOrders().add(order);  
  •             session.save(p1);  
  •             session.save(p2);  
  •             session.getTransaction().commit();  
  •         }  
  •   
  •         在这段代码中,明显可以看出关联关系的维护交给了Product来做了,这个Product.hbm.xml中配置的方式相矛盾,因此  
  •         必然会在保存数据的时候出现问题。运行这段代码,查看后台HIbernate使用的SQL语句为:  
  •   
  •         Hibernate:   
  •             select  
  •                 order0_.ID as ID6_1_,  
  •                 order0_.NAME as NAME6_1_,  
  •                 order0_.NUM as NUM6_1_,  
  •                 order0_.MEMBER_ID as MEMBER4_6_1_,  
  •                 products1_.ORDER_ID as ORDER1_3_,  
  •                 product2_.ID as PRODUCT2_3_,  
  •                 product2_.ID as ID8_0_,  
  •                 product2_.NAME as NAME8_0_   
  •             from  
  •                 TEST_ORDER order0_   
  •             left outer join  
  •                 TEST_ORDER_PRODUCT products1_   
  •                     on order0_.ID=products1_.ORDER_ID   
  •             left outer join  
  •                 TEST_PRODUCT product2_   
  •                     on products1_.PRODUCT_ID=product2_.ID   
  •             where  
  •                 order0_.ID=?  
  •         Hibernate:   
  •             insert   
  •             into  
  •                 TEST_PRODUCT  
  •                 (NAME)   
  •             values  
  •                 (?)  
  •         Hibernate:   
  •             insert   
  •             into  
  •                 TEST_PRODUCT  
  •                 (NAME)   
  •             values  
  •                 (?)  
  •         从这段SQL代码可以看出,只是进行了Product数据的插入,并没有对反映Order和Product关系的中间表进行数据  
  •         插入,看来配置文件中的设定由Order来维护关联关系起了一定的作用(为什么是一定的作用而不是完全的呢?这  
  •         是因为还没有进行必要的测试,只是在这里反映出Product已经不能维护关联关系了)。  
  •   
  •         下面我们将Java代码改动一下如下:  
  •   
  •         public void insert()  
  •         {  
  •             Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession();  
  •             session.beginTransaction();  
  •             Product p1 = new Product();  
  •             p1.setName("p1");  
  •             Product p2 = new Product();  
  •             p2.setName("p2");  
  •             Order order = (Order)session.load(Order.class, 3);  
  •             order.getProducts().add(p1);  
  •             order.getProducts().add(p2);  
  •             session.save(order);  
  •             session.getTransaction().commit();  
  •         }  
  •   
  •         再次运行,查看后台SQL语句如下:  
  •   
  •         Hibernate:   
  •             select  
  •                 order0_.ID as ID6_1_,  
  •                 order0_.NAME as NAME6_1_,  
  •                 order0_.NUM as NUM6_1_,  
  •                 order0_.MEMBER_ID as MEMBER4_6_1_,  
  •                 products1_.ORDER_ID as ORDER1_3_,  
  •                 product2_.ID as PRODUCT2_3_,  
  •                 product2_.ID as ID8_0_,  
  •                 product2_.NAME as NAME8_0_   
  •             from  
  •                 TEST_ORDER order0_   
  •             left outer join  
  •                 TEST_ORDER_PRODUCT products1_   
  •                     on order0_.ID=products1_.ORDER_ID   
  •             left outer join  
  •                 TEST_PRODUCT product2_   
  •                     on products1_.PRODUCT_ID=product2_.ID   
  •             where  
  •                 order0_.ID=?  
  •         Hibernate:   
  •             insert   
  •             into  
  •                 TEST_PRODUCT  
  •                 (NAME)   
  •             values  
  •                 (?)  
  •         Hibernate:   
  •             insert   
  •             into  
  •                 TEST_PRODUCT  
  •                 (NAME)   
  •             values  
  •                 (?)  
  •         Hibernate:   
  •             insert   
  •             into  
  •                 TEST_ORDER_PRODUCT  
  •                 (ORDER_ID, PRODUCT_ID)   
  •             values  
  •                 (?, ?)  
  •         Hibernate:   
  •             insert   
  •             into  
  •                 TEST_ORDER_PRODUCT  
  •                 (ORDER_ID, PRODUCT_ID)   
  •             values  
  •                 (?, ?)  
  •         显然,和没有使用任何inverse="true"时的情况一摸一样,是正确的,也就是说现在是由Order来维护两个关联对象的关联关系的。  
  •   
  •         对于多对多关联来说,可以在任何一端来设置为主控方,也可都不设,那么两端都可以维护关联关系(并且,我们发现和设定一方  
  •         为主控方在性能上没有什么变化)。  
  •   
  •         如果两端都设定为inverse="true"的话呢?  
  •   
  •         我们来做个测试,将两个映射文件的<set>节点的inverse属性都设置为true。对于Order来说,是让Product作为主控方;对于  
  •         Product来说让Order作为主控方。  
  •   
  •         先用下面代码测试:  
  •   
  •         public void insert()  
  •         {  
  •             Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession();  
  •             session.beginTransaction();  
  •             Product p1 = new Product();  
  •             p1.setName("p1");  
  •             Product p2 = new Product();  
  •             p2.setName("p2");  
  •             Order order = (Order)session.load(Order.class, 3);  
  •         //  order.getProducts().add(p1);  
  •         //  order.getProducts().add(p2);  
  •             p1.getOrders().add(order);  
  •             p2.getOrders().add(order);  
  •             session.save(p1);  
  •             session.save(p2);  
  •             session.getTransaction().commit();  
  •         }  
  •   
  •         查看后台SQL语句如下:  
  •   
  •         Hibernate:   
  •             select  
  •                 order0_.ID as ID6_1_,  
  •                 order0_.NAME as NAME6_1_,  
  •                 order0_.NUM as NUM6_1_,  
  •                 order0_.MEMBER_ID as MEMBER4_6_1_,  
  •                 products1_.ORDER_ID as ORDER1_3_,  
  •                 product2_.ID as PRODUCT2_3_,  
  •                 product2_.ID as ID8_0_,  
  •                 product2_.NAME as NAME8_0_   
  •             from  
  •                 TEST_ORDER order0_   
  •             left outer join  
  •                 TEST_ORDER_PRODUCT products1_   
  •                     on order0_.ID=products1_.ORDER_ID   
  •             left outer join  
  •                 TEST_PRODUCT product2_   
  •                     on products1_.PRODUCT_ID=product2_.ID   
  •             where  
  •                 order0_.ID=?  
  •         Hibernate:   
  •             insert   
  •             into  
  •                 TEST_PRODUCT  
  •                 (NAME)   
  •             values  
  •                 (?)  
  •         Hibernate:   
  •             insert   
  •             into  
  •                 TEST_PRODUCT  
  •                 (NAME)   
  •             values  
  •                 (?)  
  •         看来没有对中间表进行数据插入。  
  •   
  •         使用下面代码来测试:  
  •   
  •         public void insert()  
  •         {  
  •             Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession();  
  •             session.beginTransaction();  
  •             Product p1 = new Product();  
  •             p1.setName("p1");  
  •             Product p2 = new Product();  
  •             p2.setName("p2");  
  •             Order order = (Order)session.load(Order.class, 3);  
  •             order.getProducts().add(p1);  
  •             order.getProducts().add(p2);  
  •   
  •             session.save(order);  
  •             session.getTransaction().commit();  
  •         }  
  •   
  •         查看后台的SQL语句如下:  
  •   
  •         Hibernate:   
  •             select  
  •                 order0_.ID as ID6_1_,  
  •                 order0_.NAME as NAME6_1_,  
  •                 order0_.NUM as NUM6_1_,  
  •                 order0_.MEMBER_ID as MEMBER4_6_1_,  
  •                 products1_.ORDER_ID as ORDER1_3_,  
  •                 product2_.ID as PRODUCT2_3_,  
  •                 product2_.ID as ID8_0_,  
  •                 product2_.NAME as NAME8_0_   
  •             from  
  •                 TEST_ORDER order0_   
  •             left outer join  
  •                 TEST_ORDER_PRODUCT products1_   
  •                     on order0_.ID=products1_.ORDER_ID   
  •             left outer join  
  •                 TEST_PRODUCT product2_   
  •                     on products1_.PRODUCT_ID=product2_.ID   
  •             where  
  •                 order0_.ID=?  
  •         Hibernate:   
  •             insert   
  •             into  
  •                 TEST_PRODUCT  
  •                 (NAME)   
  •             values  
  •                 (?)  
  •         Hibernate:   
  •             insert   
  •             into  
  •                 TEST_PRODUCT  
  •                 (NAME)   
  •             values  
  •                 (?)  
  •         比较两次的结果,发现一摸一样。看来如果两端都设置为主控方,是不能对中间表进行数据保存的。  
  •   
  •         b、数据加载  
  •   
  •         数据加载就不再演示了,也就是默认采用左外连接的方式加载数据,能够将Order和它的关联对象  
  •         Product都加载,当然是通过中间表;对于Product来说也是这样。  
  •   
  •         c、删除数据  
  •   
  •         删除数据也不再演示,无论删除Order还是Product,都是简单的删除自己,而不会删除关联的对象  
  •         ,这是因为设定了cascade="save-update"

     
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值