现在的位置: 首页 > 综合 > 正文

7、hibernate中的关联关系

2017年11月30日 ⁄ 综合 ⁄ 共 12756字 ⁄ 字号 评论关闭

hbm.xml文件可以完成多种映射关系的映射

- 创建具有一对多关联关系的域模型
-创建具有一对多参照关系的关系模型
-映射一对多关联关系
-通过Hibernate API级联操纵具有关联关系的域对象。(级联操纵:一的一方删除,多的一方同时删除)

1、一对多的关联关系(一对一是一对多的特殊情况)

Customer和Order的一对多双向关联(双向:你中有我,我中有你),一个用户可以有多个订单,一个订单只能属于一个用户

创建两个类:

import java.util.Set;

public class Customer
{
	private Long id;
	
	private String name;
	
	private Set<Order> orders; //一对多,通过该变量可以引用到对应的Order集合对象

	public Long getId()
	{
		return id;
	}

	public void setId(Long id)
	{
		this.id = id;
	}

	public String getName()
	{
		return name;
	}

	public void setName(String name)
	{
		this.name = name;
	}

	public Set<Order> getOrders()
	{
		return orders;
	}

	public void setOrders(Set<Order> orders)
	{
		this.orders = orders;
	}
}

 

public class Order
{
	private Long id;
	
	private String orderNumber;
	
	private Customer customer; //多对一,通过该变量可以引用到对应的customer对象

	public Long getId()
	{
		return id;
	}

	public void setId(Long id)
	{
		this.id = id;
	}

	public String getOrderNumber()
	{
		return orderNumber;
	}

	public void setOrderNumber(String orderNumber)
	{
		this.orderNumber = orderNumber;
	}

	public Customer getCustomer()
	{
		return customer;
	}

	public void setCustomer(Customer customer)
	{
		this.customer = customer;
	}
	
	
}

创建两个数据库表:

CREATE TABLE `customers` (
  `ID` bigint(20) NOT NULL,
  `NAME` varchar(50) default NULL,
  PRIMARY KEY  (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

 

CREATE TABLE `orders` (
  `ID` bigint(20) NOT NULL,
  `ORDER_NUMBER` varchar(15) default NULL,
  `CUSTOMER_ID` bigint(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


创建对应类的hbm.xml文件:

Customer.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
	
	<class name="com.cdtax.hibernate.Customer" table="customers">
	
		<id name="id" column="id" type="long">
			<generator class="increment"></generator>
		</id>
		
		<property name="name" type="string">
			<column name="name" length="50"></column>
		</property>
		
		<set name="orders" cascade="save-update" inverse="true">
			<key column="customer_id"></key>
			<one-to-many class="com.cdtax.hibernate.Order"/>
		</set>
	</class>
</hibernate-mapping>

Order.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
	
	<class name="com.cdtax.hibernate.Order" table="orders">
	
		<id name="id" column="id" type="long">
			<generator class="increment"></generator>
		</id>
		
		<property name="orderNumber" type="string">
			<column name="order_number" length="15"></column>
		</property>
		
		<many-to-one name="customer" class="com.cdtax.hibernate.Customer" column="customer_id">
		</many-to-one>
	</class>
</hibernate-mapping>

创建测试类:

import java.util.HashSet;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

public class HibernateTest
{
	private static SessionFactory sessionFactory;

	static
	{
		try
		{
			sessionFactory = new Configuration().configure()
					.buildSessionFactory();
		} catch (Exception ex)
		{
			ex.printStackTrace();
		}
	}

	public static void main(String[] args) throws Exception
	{
		Session session = sessionFactory.openSession();

		Transaction tx = null;
		
		try
		{
			tx = session.beginTransaction();
			
			Customer customer = new Customer();
			customer.setName("zhangsan");
			customer.setOrders(new HashSet());
			
			Order order1 = new Order();
			order1.setOrderNumber("order1");
			
			Order order2 = new Order();
			order2.setOrderNumber("order2");
			
			Order order3 = new Order();
			order3.setOrderNumber("order3");
			
			order1.setCustomer(customer);
			order2.setCustomer(customer);
			order3.setCustomer(customer);
			
			customer.getOrders().add(order1);
			customer.getOrders().add(order2);
			customer.getOrders().add(order3);
			
			session.save(customer);
			tx.commit();
			
			
		}
		catch(Exception ex)
		{
			if(null != tx)
			{
				tx.rollback();
			}
			ex.printStackTrace();
		}
		finally
		{
			session.close();
		}
	}

}

重点要理解的是hbm.xml文件

对于Customer.hbm.xml:

<hibernate-mapping>
 
 <class name="com.cdtax.hibernate.Customer" table="customers"> : 这一句class标签表示对类整体进行映射,name指出映射的域模型,即类名,table指出类映射到的关系模型即与哪张表映射。
 
  <id name="id" column="id" type="long">
   <generator class="increment"></generator>
  </id>
  id标签定义关键字,name是类的OID,column是表的主键,generator指出主键的生成方式。

  <property name="name" type="string">
   <column name="name" length="50"></column>
  </property>
  property标签定义类的普通属性映射关系,name是类的属性名,column是对应表的列名

  <set name="orders" cascade="save-update" inverse="true">
   <key column="customer_id"></key>
   <one-to-many class="com.cdtax.hibernate.Order"/>
  </set>
  set是一个很关键的标签,在一对多的映射中,一的一方(这里就是指Customer类)要包含多的一方(Order类),那么一的一方的属性就应该是一个集合,所以用set来表示,set的name属性是一的一方的属性名,这里就是Customer类中的orders属性,cascade是级联关系,就是指出当我对一的一方进行保存或更新时,多的一方是否同时进行操作,可以有很多值,save-update表示同时操作,none表示不级联,等等,inverse是反转的意思,默认值为false,就是说一对多的关系由一的一方维护,如果改为true,则由多的一方维护,一般一对多的一方都设为true,即反转。
  one-to-many标签指出一的一方包含多的一方的属性(应该是一个集合类型)集合中对象的类型,用class来指出集合对象的类型,对于Customer的orders属性,集合中的对象类型为Order类型。可以这样理解,看源代码定义:
                  private Set<Order> orders;这里使用了泛型,所以我们一看就知道orders中保存的是Order对象,如果不使用泛型,我们看不出来,机器也无从分辨,所以class就是指出泛型的具体类型。
  key子标签的column属性是指出多的一方(这里就是Order)是根据多方对应的表(orders表)的哪一列来查询的,也就是多的一方对应一的一方的外键,如我查询id为1的一方(从customers表中),因为还有一个orders属性,这个属性的值就是根据相应的查询id关联到多的一方的外键,即customer_id查询出来的。
  用SQL来表示,就是第一步:select * from customers where id = 1,因为这个表里没有Order信息,所以还要:select * from orders where customer_id = 1,这里的<key column="customer_id"></key>的column值就是orders表的customer_id,外键。

 </class>
</hibernate-mapping>

 

对于Order.hbm.xml,需要注意的是

<many-to-one name="customer" class="com.cdtax.hibernate.Customer" column="customer_id">
  </many-to-one>

这是关系映射中的多的一方对包含的一的一方属性的映射定义,name指出多的一方(Order)的属性名,即Order类中private Customer customer;,class相当于普通属性映射property标签中的type,定义属性类型,column定义与orders表的哪一列关联。

执行测试类HibernateTest,结果:

Hibernate: select max(id) from customers
Hibernate: select max(id) from orders
Hibernate: insert into customers (name, id) values (?, ?)
Hibernate: insert into orders (order_number, customer_id, id) values (?, ?, ?)
Hibernate: insert into orders (order_number, customer_id, id) values (?, ?, ?)
Hibernate: insert into orders (order_number, customer_id, id) values (?, ?, ?)
可以看出,我们只是执行了save(customer),而插入表时进行级联操作,同时将关联的3个order插入了orders表。

 

如果我们将Customer.hbm.xml中的set进行修改,将cascade值改为none,

<set name="orders" cascade="none" inverse="true">
   <key column="customer_id"></key>
   <one-to-many class="com.cdtax.hibernate.Order"/>
  </set>

执行结果:

Hibernate: select max(id) from customers
Hibernate: insert into customers (name, id) values (?, ?)

只进行了customers表的插入。

2、延迟加载

对customer进行查询:

修改HibernateTest的main方法

Session session = sessionFactory.openSession();
		Customer customer = null;
		Transaction tx = null;
		
		try
		{
			tx = session.beginTransaction();
			
			customer = (Customer)session.get(Customer.class, new Long(1));
			tx.commit();
			
			
		}
		catch(Exception ex)
		{
			if(null != tx)
			{
				tx.rollback();
			}
			ex.printStackTrace();
		}
		finally
		{
			session.close();
		}
		
		System.out.println(customer.getName());
	}

执行结果:

Hibernate: select customer0_.id as id0_0_, customer0_.name as name0_0_ from customers customer0_ where customer0_.id=?
zhangsan
只执行了一次查询

继续修改:

Session session = sessionFactory.openSession();
		
		Transaction tx = null;
		
		try
		{
			tx = session.beginTransaction();
			
			Customer customer = (Customer)session.get(Customer.class, new Long(1));
			
			System.out.println(customer.getName());
			
			tx.commit();
			
			
		}
		catch(Exception ex)
		{
			if(null != tx)
			{
				tx.rollback();
			}
			ex.printStackTrace();
		}
		finally
		{
			session.close();
		}
		
		
	}

执行结果:

Hibernate: select customer0_.id as id0_0_, customer0_.name as name0_0_ from customers customer0_ where customer0_.id=?
zhangsan

执行了一次查询

继续修改:

try
		{
			tx = session.beginTransaction();
			
			Customer customer = (Customer)session.get(Customer.class, new Long(1));
			
			System.out.println(customer.getName());
			System.out.println(customer.getOrders());
			tx.commit();
			
			
		}

执行结果:
Hibernate: select customer0_.id as id0_0_, customer0_.name as name0_0_ from customers customer0_ where customer0_.id=?
zhangsan
Hibernate: select orders0_.customer_id as customer3_1_, orders0_.id as id1_, orders0_.id as id1_0_, orders0_.order_number as order2_1_0_, orders0_.customer_id as customer3_1_0_ from orders orders0_ where orders0_.customer_id=?
[com.cdtax.hibernate.Order@110003, com.cdtax.hibernate.Order@12d96f2, com.cdtax.hibernate.Order@17e4ca]

修改:

Session session = sessionFactory.openSession();
		
		Transaction tx = null;
		
		try
		{
			tx = session.beginTransaction();
			
			Customer customer = (Customer)session.get(Customer.class, new Long(1));
			
			System.out.println(customer.getName());
			
			Set<Order> orders = customer.getOrders();
			
			for(Iterator iter = orders.iterator();iter.hasNext();)
			{	
				Order order =(Order) iter.next();
				System.out.println(order.getOrderNumber());
			}
			tx.commit();
			
			
		}
		catch(Exception ex)
		{
			if(null != tx)
			{
				tx.rollback();
			}
			ex.printStackTrace();
		}
		finally
		{
			session.close();
		}

执行结果:

Hibernate: select customer0_.id as id0_0_, customer0_.name as name0_0_ from customers customer0_ where customer0_.id=?
zhangsan
Hibernate: select orders0_.customer_id as customer3_1_, orders0_.id as id1_, orders0_.id as id1_0_, orders0_.order_number as order2_1_0_, orders0_.customer_id as customer3_1_0_ from orders orders0_ where orders0_.customer_id=?
order2
order3
order1

修改:

Session session = sessionFactory.openSession();
		Customer customer = null;
		Transaction tx = null;
		
		try
		{
			tx = session.beginTransaction();
			
			customer = (Customer)session.get(Customer.class, new Long(1));
			
			System.out.println(customer.getName());
			
			
			tx.commit();
			
			
		}
		catch(Exception ex)
		{
			if(null != tx)
			{
				tx.rollback();
			}
			ex.printStackTrace();
		}
		finally
		{
			session.close();
		}
		
		Set<Order> orders = customer.getOrders();
		
		for(Iterator iter = orders.iterator();iter.hasNext();)
		{	
			Order order =(Order) iter.next();
			System.out.println(order.getOrderNumber());
		}
	}

执行结果:

Hibernate: select customer0_.id as id0_0_, customer0_.name as name0_0_ from customers customer0_ where customer0_.id=?
zhangsan
Exception in thread "main" org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.cdtax.hibernate.Customer.orders, no session or session was closed
 at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380)
 at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372)
 at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:365)
 at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:108)
 at org.hibernate.collection.PersistentSet.iterator(PersistentSet.java:186)
 at com.cdtax.hibernate.HibernateTest.main(HibernateTest.java:112)
出现异常

修改:

Session session = sessionFactory.openSession();
		Customer customer = null;
		Transaction tx = null;
		
		try
		{
			tx = session.beginTransaction();
			
			customer = (Customer)session.get(Customer.class, new Long(1));
			
			System.out.println(customer.getName());
			
			Set set = customer.getOrders();
			
			System.out.println(set);
			
			tx.commit();
			
			
		}
		catch(Exception ex)
		{
			if(null != tx)
			{
				tx.rollback();
			}
			ex.printStackTrace();
		}
		finally
		{
			session.close();
		}
		
		Set<Order> orders = customer.getOrders();
		
		for(Iterator iter = orders.iterator();iter.hasNext();)
		{	
			Order order =(Order) iter.next();
			System.out.println(order.getOrderNumber());
		}
	}

结果:

Hibernate: select customer0_.id as id0_0_, customer0_.name as name0_0_ from customers customer0_ where customer0_.id=?
zhangsan
Hibernate: select orders0_.customer_id as customer3_1_, orders0_.id as id1_, orders0_.id as id1_0_, orders0_.order_number as order2_1_0_, orders0_.customer_id as customer3_1_0_ from orders orders0_ where orders0_.customer_id=?
[com.cdtax.hibernate.Order@110003,
com.cdtax.hibernate.Order@adb1d4
,
com.cdtax.hibernate.Order@17e4ca
]
order1
order2
order3

3、异常:LazyInitializationException延迟初始化异常

Hibernate中的延迟加载(Lazy Loading),当我们在程序中获取到了一的一方,但是不需要多的一方,那么使用延迟加载就是非常适合的。

相对应的就是立即加载

修改hbm.xml文件:

<set name="orders" cascade="save-update" inverse="true" lazy="false">
   <key column="customer_id"></key>
   <one-to-many class="com.cdtax.hibernate.Order"/>
  </set>

加上lazy=“false”就可以实现立即加载。

4、查询多的一方:

Session session = sessionFactory.openSession();
	
		Transaction tx = null;
		
		Order order = null;
		Customer customer = null;
		
		try
		{
			tx = session.beginTransaction();
			
			order = (Order)session.get(Order.class, new Long(1));
			System.out.println(order.getOrderNumber());
			customer = order.getCustomer();
			tx.commit();
			
		}
		catch(Exception ex)
		{
			if(null != tx)
			{
				tx.rollback();
			}
			ex.printStackTrace();
		}
		finally
		{
			session.close();
		}
		
		System.out.println(customer.getName());
	}

结果:

Hibernate: select order0_.id as id1_0_, order0_.order_number as order2_1_0_, order0_.customer_id as customer3_1_0_ from orders order0_ where order0_.id=?
order1
Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session
 at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:132)
 at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:174)
 at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
 at com.cdtax.hibernate.Customer_$$_javassist_0.getName(Customer_$$_javassist_0.java)
 at com.cdtax.hibernate.HibernateTest.main(HibernateTest.java:153)

如果将Order.hbm.xml修改:

<many-to-one name="customer" class="com.cdtax.hibernate.Customer" column="customer_id" lazy="false">
  </many-to-one>

结果:

Hibernate: select order0_.id as id1_0_, order0_.order_number as order2_1_0_, order0_.customer_id as customer3_1_0_ from orders order0_ where order0_.id=?
Hibernate: select customer0_.id as id0_0_, customer0_.name as name0_0_ from customers customer0_ where customer0_.id=?
Hibernate: select orders0_.customer_id as customer3_1_, orders0_.id as id1_, orders0_.id as id1_0_, orders0_.order_number as order2_1_0_, orders0_.customer_id as customer3_1_0_ from orders orders0_ where orders0_.customer_id=?
order1
zhangsan

cascade取值:

抱歉!评论已关闭.