Hibernate笔记整理 一对多(单向)

 
///
Hibernate:
	///
	一对多关联和多对一关联在实际应用中式非常普遍的。例如一个会员(Member)可以有多个订单(Order),而每个订单只能属于某个特定的会员,这便是一个典型的一对多关联。
	本示例要用到的两个POJO类如下:
	public class Member
	{
		private String id;
		private String name;
		private Integer age;
		private Set<Order> orders = new HashSet<Order>();
	    ......
	}

	public class Order
	{
		private Integer id;
		private String name;
		private String num;
		private String memberId;//没有Member对象
		......
	}
	
	会员(Member)拥有多个订单(Order),而每个订单只能属于某个特定的会员。
	首先来演示和学习一对多的单向关联。
	两个人POJO的映射文件如下:
	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属性值是对应的POJO中的相关属性名称-->
			<set name="orders" cascade="all">
				<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>
			<!--外键-->
			<property name="memberId" column="MEMBER_ID"></property>
		</class>
	</hibernate-mapping>

	在Member.hbm.xml中主要的是它的<set>元素,它定义了Order作为它的一个集合属性。而Order.hbm.xml则和普通的映射文件没有什么不同。
	下面进行测试:
	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");
        
        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
	        (?, ?, ?)
	Hibernate: 
	    update
	        TEST_ORDER 
	    set
	        MEMBER_ID=? 
	    where
	        ID=?

	总共执行了3条Sql语句,前两条是进行数据的插入,第三条将Order的外键更新为Member的主键值。
	因为关联关系时单向的,关联关联关系由Member来维护,而“多”的一方并不知道它自己和Member有任何关系。
	在这个例子中,Hibernate首先向数据库插入Member的数据,然后插入Order的数据(这时候Order的外键为
	NULL,如果设置其外键不允许为NULL的话就会报错),最后Hibernate会发送一条更新Order外键的Sql语句,
	其值由Member的主键值而来。由此看出采用这种单向关联存在着很大的问题,包括性能、是否为空等问题。

	b、加载数据

	public void getMemberById(String id)
	{
        Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        Member m = (Member)session.load(Member.class, id);
        System.out.println(m+"/n"+m.getOrders().size());
        session.getTransaction().commit();
    } 
	查看后台的SQL语句:

	Hibernate: 
	    select
	        member0_.ID as ID5_1_,
	        member0_.AGE as AGE5_1_,
	        member0_.NAME as NAME5_1_,
	        idcard1_.ID as ID4_0_,
	        idcard1_.NUM as NUM4_0_,
	        idcard1_.MEMBER_ID as MEMBER3_4_0_ 
	    from
	        TEST_MEMBER member0_ 
	    left outer join
	        TEST_IDCARD idcard1_ 
	            on member0_.ID=idcard1_.MEMBER_ID 
	    where
	        member0_.ID=?
	Hibernate: 
	    select
	        orders0_.MEMBER_ID as MEMBER4_1_,
	        orders0_.ID as ID1_,
	        orders0_.ID as ID6_0_,
	        orders0_.NAME as NAME6_0_,
	        orders0_.NUM as NUM6_0_,
	        orders0_.MEMBER_ID as MEMBER4_6_0_ 
	    from
	        TEST_ORDER orders0_ 
	    where
	        orders0_.MEMBER_ID=?

	这里有点要注意:m.getOrders()在这里必须要在加载Member对象的Session范围内,否则得话就会出错,因为Session已经关闭。

	c、删除数据
	
	public void delete(String id) 
	{
		Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession();
		session.beginTransaction();
		Member m = (Member) session.load(Member.class, id);
		session.delete(m);
		session.getTransaction().commit();
	}

	查看Hibernate后台SQL语句如下:
	
	Hibernate: 
	    select
	        member0_.ID as ID5_1_,
	        member0_.AGE as AGE5_1_,
	        member0_.NAME as NAME5_1_,
	        idcard1_.ID as ID4_0_,
	        idcard1_.NUM as NUM4_0_,
	        idcard1_.MEMBER_ID as MEMBER3_4_0_ 
	    from
	        TEST_MEMBER member0_ 
	    left outer join
	        TEST_IDCARD idcard1_ 
	            on member0_.ID=idcard1_.MEMBER_ID 
	    where
	        member0_.ID=?
	Hibernate: 
	    select
	        orders0_.MEMBER_ID as MEMBER4_1_,
	        orders0_.ID as ID1_,
	        orders0_.ID as ID6_0_,
	        orders0_.NAME as NAME6_0_,
	        orders0_.NUM as NUM6_0_,
	        orders0_.MEMBER_ID as MEMBER4_6_0_ 
	    from
	        TEST_ORDER orders0_ 
	    where
	        orders0_.MEMBER_ID=?
	Hibernate: 
	    update
	        TEST_ORDER 
	    set
	        MEMBER_ID=null 
	    where
	        MEMBER_ID=?
	
	Hibernate: 
	    delete 
	    from
	        TEST_ORDER 
	    where
	        ID=?
	Hibernate: 
	    delete 
	    from
	        TEST_MEMBER 
	    where
	        ID=?

	因为我根据一个Member的主键来加载到它的一个对象实例,然后将其删除,所以Hibernate首先加载Member对象及其Order集合;因为要删除Order,
	所以又更新了Order的外键为NULL,最后删除Order和Member。可见删除一个会员会执行大量的SQL语句,对性能的影响可想而知,并且如果Order的外键不允许为NULL,
	那么在更新Order时就会报错,这些都是要考虑的。而理想的情况应该是这样的:首先取出Member和其相关的集合,让后逐个删除与Member关联的对象,最后删除Member,
	比起上面的少了大量的更新语句,显然性能上要有所提高。

	为了能够达到上述理想情况,使用这种单向关联是不行的,那就要通过双向关联来实现。

	注:如果Member有上千个订单的话就要一条一条的删除订单,性能上也会受影响,幸好,Hibernate提高了一个系统属性可以设置成用来进行批量更新。
	hibernate.jdbc.batch_size,Hibernate官方建议取值在5和30之间。只有当要执行的SQL语句到指定的数目后,Hibernate才将其提交执行,
	这样减少了与数据交互的次数,从而提高性能。
	
	

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值