天天看點

Hibernate關聯關系一、單向N-1二、單向的1-1三、單向的1-N四、單向N-N懶加載删除對應資料hibernate架構一對多的執行原理

Hibernate關聯就是将關聯映射到資料庫,所謂關聯關系就是對象模型在記憶體中的一個或多個引用。

先看兩個關系實體類: 都提供set/get方法

public class Order {
	private Integer orderId;
	private String orderNo;
	private List<OrderItem> orderItems = new ArrayList<>();
	private Integer initChildren =0;  //0代表懶加載  預設為0
	
}
           
public class OrderItem {
	private Integer orderItemId;
	private Integer productId;
	private Integer quantity;
	private Integer oid;
	private Order order;
}
           

下面介紹幾種單向的關聯關系。

文章目錄

  • 一、單向N-1
  • 二、單向的1-1
  • 三、單向的1-N
  • 四、單向N-N
  • 懶加載
  • 删除對應資料
  • hibernate架構一對多的執行原理

一、單向N-1

所謂的單向1-N,也就是一個a實體類中有可以有多個b實體類的關系。

xml配置:

<many-to-one name="orderItem" column="productId"/>
           

二、單向的1-1

這種情況也是使用many-to-one,

不過在标簽中多加一個unique=true這個屬性,

這個屬性代表的是限制了多的一端的多重性唯一。

通過這種手段可以映射一對一唯一外鍵關聯。

xml配置:

<many-to-one name="address" column="oid" unique="true"/>
           

三、單向的1-N

一對多關聯映射,在多的一端添加一個外鍵指向一的一端,它維護的關系是一指向多。

xml配置:

<!-- 
	bag标簽:
		 lazy:是否懶加載,預設是懶加載
		 name:類的關聯屬性名
		 cascade:級聯關系  級聯新增與修改
		 inverse:關聯關系交給對方控制,預設是true  意思就是目前類不維護關聯關系
		 
		 子标簽key:
		 	column:主表的主鍵,從表的外鍵。一般寫從表的外鍵
		 子标簽one-to-many:
		 	class:外鍵對應的實體類
		 
 -->
	<bag lazy="true" name="orderItems" cascade="save-update" inverse="true">
		<key column="oid"></key>
		<one-to-many class="com.zlk.three.entity.OrderItem"/>
	</bag>
           

在這裡有兩個選擇,可以選擇bag标簽也可以使用set标簽,

bag是一個無序的集合,它可以包含重複的元素,相當于java的java.util.List。

set類似于bag,但它隻能存儲唯一對象,若元素相同,則新的會替換掉舊的元素。類似Java中的java.util.Set。

四、單向N-N

兩個實體類:

public class User {
	private int id;
	private String name;
	private Set roles;
}
           
public class Role {
private int id;
private String name;
}
           

現在需要映射這樣的N-N關系,一個User可以有多個Role,而一個Role有可以被多個User所擁有。

這樣我們就可以将一個N-N關系拆分為兩個N-1的關系。

xml配置:

<bag name="roles" table="t_user_role">
<key column="userid"/>
<many-to-many class="xxx.Role" column="roleid"/>
</bag>
           

參考在這,想了解更多關系,請參考如何了解hibernate關聯關系。

懶加載

四種模式已經介紹完了,在這裡我先着重講解一下1-N。

在1-N的xml配置中:

<bag lazy="true" name="orderItems" cascade="save-update" inverse="true">
			<key column="oid"></key>
			<one-to-many class="com.zlk.three.entity.OrderItem"/>
		</bag>
           

上面介紹過lazy是懶模式。他預設是true,那什麼是懶模式呢?

當lazy= false 的時候,會讓hibernate執行完兩次操作,session才會關閉,

當lazy= true 的時候,會讓hibernate執行完一次操作,session就會關閉

為什麼要預設true呢?

出于性能的考慮,是以hibarnate3.0出現lazy這個屬性,并讓他預設等于true,也就是不加載關聯屬性。

可以使用JUnit測試一下,

@Test
	public void testGetOrder() {
		Order order = new Order();
		order.setOrderId(1);
		Order o = this.demoDao.getOrder(order );
		List<OrderItem> orderItems = o.getOrderItems();
		for (OrderItem orderItem : orderItems) {
			System.out.println(orderItem);
		}
		System.out.println(o);
	}
           

當lazy=false時候,他會正常運作,并列印出資料。

當lazy=true時候,他會報no-Session錯,這是因為允許了懶加載,隻執行了一次操作,是以 List orderItems = o.getOrderItems();這裡面是沒有值的,

但如果我隻是單純的寫要查出所有的訂單那怎麼辦呢?

這裡就運用到了上面實體類中的private Integer initChildren =0; //0代表懶加載 預設為0。

通過這個屬性來控制是否強制加載關聯對象。

public Order getOrder(Order order) {
		Session session = SessionFactoryUtils.openSession();
		Transaction transaction = session.beginTransaction();
		Order o = session.get(Order.class, order.getOrderId());
		if(o != null && new Integer(1).equals(order.getInitChildren())) {
			//強制加載關聯對象
			Hibernate.initialize(o.getOrderItems());
		}
		transaction.commit();
		session.close();
		return o;
	}
           

這樣就可以使用懶加載檢視所有訂單了。

删除對應資料

若你想删除訂單的時候,這時候不能直接删除訂單,因為你的從表OrderItem裡面還是有資料的,是以你必須先删除從表裡面的值,才可以删除order。

方法如下:

public void delOrder(Order order) {
		Session session = SessionFactoryUtils.openSession();
		Transaction transaction = session.beginTransaction();
		Order order2 = session.get(Order.class, order.getOrderId());
		for (OrderItem oi : order2.getOrderItems()) {
			session.delete(oi);
		}
		session.delete(order2);
		transaction.commit();
		session.close();
	}
           

hibernate架構一對多的執行原理

hibernate架構一對多的執行原理:

1,對hibernate.cfg.xml進行模組化,等到sessionfactory對象

2,并且拿到mapping resourse裡的内容

3,拿到order.hbm.xml配置檔案

4,可以再次模組化,拿到實體類屬性和對應的資料庫表列段

5,生成動态的sql:select * 表名

執行sql最終得到meterData原資料模型

6,通過實體類進行反射 Class.forName(“com.zlk.three.entity.Order”).newInstance(0);

獲得所有資料庫内的資料。

最終得到List,且裡面都有值(到這裡隻是處理了表裡面的非外鍵列段)

7,處理關聯關系 :通過标簽獲得orderItems(所有訂單) oid 和訂單實體類com.zlk.three.entity.OrderItem

然後通過one-to-many 裡的 class(也就是com.zlk.three.entity.OrderItem),就可獲得這個實體類的xml,

再通過這個xml獲得對應的資料庫表。

8,與第五步相同,最終獲得了一個list

9,給order的關聯關系屬性指派

就是在第六步中獲得List時,一個一個的加進去:

for(Order o:List){

o.setOrderItems(List );

}

繼續閱讀