簡單解析hibernate中的一對多關係
-
什麼是關聯(association)
1.1 關聯指的是類之間的引用關係。如果類A與類B關聯,那麼被引用的類B將被定義為類A的屬性。例如:
public class A{
private B b = new B;
public A(){}
}
1.2 關聯的分類:關聯可以分為一對一、一對多/多對一、多對多關聯
關聯是有方向的訂單表、訂單項表
select * from t_order t,t_orderItem m where t.oid = m.oid
and …class Order{
private STIRNG OID;
…
private Set OrderItems;
}session.get(Order.class,1)
呼叫此方法
將關聯屬性自動賦值。
#關鍵點都在資料庫中的外來鍵上面,請好好理解下面這二句SQL和一對多及多對一的關係
#select * from Orders where cid=? //這條SQL返回客戶對應的0-n個訂單
#select * from Customers where customerId=? //這條SQL返回訂單對應的1個客戶
#通過這二條SQL不難看出,外來鍵在這裡有二個用途:查詢客戶的訂單,查詢訂單對應的客戶
2. 案例:如何建立客戶和訂單一對多雙向關聯
2.1 先不建立客戶和訂單的關聯關係,定義實體及對映檔案,單獨執行儲存操作
2.2 建立客戶到訂單的一對多關聯關係
2.3 建立訂單到客戶的多對一關聯關係
<!--1.註釋 2.只讀-->
<property name="cid" type="java.lang.Integer" column="cid" insert="false" update="false">
</property>
2.4 注意:在Hibernate當中定義實體物件的集合屬性時,只能使用介面而不能使用類
#insert屬性設定中主控方概念理解:
3. 以客戶和訂單的一對多雙向關聯為例,講解Set元素中的cascade|inverse|outter-join|lazy屬性作用
3.1 lazy:預設值為true,true延遲載入,false立即載入(一般設定為true,不使用立即載入,因為影響查詢效能)
3.2 outter-join:預設值為false,true使用左外聯接查詢關聯的(但一般不用,因為當我們把該屬性設定為true時,所有的查詢語句都會預設左外聯,那樣效能不高)
3.3 inverse:預設值為false,true表示將對方設定為主控方(一對多雙向關聯中一般將多方設定為主控方,這樣可以減少SQL語句的數量,減少多餘的操作)
3.4 cascade:用來控制如何操作關聯的持久化物件的
3.4.1 none:儲存,更新或刪除當前物件時,忽略其它關聯的物件
3.4.2 save-update:儲存、更新時級聯儲存所有的臨時物件,並且級聯更新關聯的遊離物件
3.4.3 delete:通過session的delete方法刪除當前物件,級聯刪除關聯的物件
3.4.4 all:等於save-update操作+delete操作
小結:
多方的CRUD與沒有建立關聯關係之前的操作一致
一方的CRUD與沒有建立關聯關係之前的操作有變化
D:刪除一方之前先刪除多方
C:級聯操作
R:程式碼控制多方
-
案例:選單物件的一對多雙向自關聯
-
如何將多方對映成一個有序的集合
核心
訂單表、訂單項
級聯新增
外來鍵處理的三種方式
1、刪除從表對應的實體類中的外來鍵屬性
2、在配置的xml中外來鍵屬性上新增 insert=false,update=false的設定。
3、在配置的xml中的manyToOne標籤中新增insert=false,update=false的設定。
級聯新增 casecade=save-update 介紹
級聯查詢
配置檔案介紹以及後臺sql的形成過程
級聯查詢時的問題
Lazy=true介紹 查單個時存在問題
Lazy=false介紹 查所有時存在問題
解決方案:通過欄位控制,強制載入。Hibernate.initialize()
普通刪除
Order
Add 講外來鍵的處理
Get/list order.getOrderItems.size講懶載入的處理,sql形成過程
Del 將關係的處理中的刪除
如程式碼演示:
package com.zking.util;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
/**
* hibernate工具類
* 未整合框架前使用
* @author Administrator
*
*/
public class HibernateUtli {
private static SessionFactory sessionFactory;
/**
* 存放當前會話
*/
private static ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
/**
* 通過單例管理sessionFactory,整個系統執行過程中只會構建一個sessionFactory物件
*/
static {
//讀取配置檔案 獲取會話 開啟事務
sessionFactory = new Configuration().configure().buildSessionFactory();
}
/**
* 建模 獲取sessionfactory
* @return
* 2018年10月19日上午10:23:16
*/
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
/**
* 開啟一個session
* @return
* 2018年10月19日上午10:20:58
*/
public static Session openSession() {
Session session = threadLocal.get();
if (null == session) {
session = sessionFactory.openSession();
threadLocal.set(session);
}
return session;
}
/**
* 開啟與執行緒繫結的session
* @return
* 2018年10月19日上午10:24:32
*/
public static Session getCurrentSession() {
Session session = threadLocal.get();
if (null == session) {
session = sessionFactory.openSession();// 如果session為空就建立一個session
threadLocal.set(session);// 放到當前的執行緒中
return session;
}
return session;
}
/**
* 關閉session
*
* 2018年10月19日上午10:21:17
*/
public static void closeSession() {
Session session = threadLocal.get();
if (null != session) {
if (session.isOpen()) {
Transaction transaction = session.beginTransaction();
transaction.commit();
session.close();
}
threadLocal.set(null);
}
}
/**
* 測試
* @param args
* 2018年10月19日上午10:25:41
*/
public static void main(String[] args) {
Session session = openSession();
System.out.println(session.isConnected());
closeSession();
}
}
package com.zking.dao.daoImpl;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.zking.entity.Order;
import com.zking.entity.OrderItem;
import com.zking.util.HibernateUtli;
public class OrderDaoImpl implements IOrderDaoImpl {
@Override
public Integer insertOrder(Order order) {
Session session = HibernateUtli.getCurrentSession();
Transaction transaction = session.beginTransaction();
Integer save = 0;
try {
save = (Integer) session.save(order);
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
throw new RuntimeException("新增出現異常");
}
HibernateUtli.closeSession();
return save;
}
@Override
public void deleteOrder(Order order) {
Session session = HibernateUtli.getCurrentSession();
Transaction transaction = session.beginTransaction();
try {
Order o = session.get(Order.class, order.getOrder_id());
System.out.println(o);
for (OrderItem ot : o.getOrderItem()) {
session.delete(ot);
}
session.delete(order);
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
throw new RuntimeException("刪除出現異常");
}
HibernateUtli.closeSession();
}
@Override
public void editOrder(Order order) {
Session session = HibernateUtli.getCurrentSession();
Transaction transaction = session.beginTransaction();
try {
session.update(order);
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
throw new RuntimeException("修改出現異常");
}
HibernateUtli.closeSession();
}
@Override
public Order getOrder(Order order) {
Session session = HibernateUtli.getCurrentSession();
Transaction transaction = session.beginTransaction();
Order t = null;
try {
t = session.get(Order.class, order.getOrder_id());
if (t != null && new Integer(1).equals(order.getInitorderItem())) {
//強制立即載入
Hibernate.initialize(t.getOrderItem());
}
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
throw new RuntimeException("查詢出現異常");
}
HibernateUtli.closeSession();
return t;
}
@Override
public List<Order> getOrderList(String str) {
Session session = HibernateUtli.getCurrentSession();
Transaction transaction = session.beginTransaction();
List<Order> list = null;
try {
Criteria criteria = session.createCriteria(Order.class);
list = criteria.list();
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
throw new RuntimeException("查詢出現異常");
}
HibernateUtli.closeSession();
return list;
}
}
package com.zking.dao.daoImpl;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.zking.entity.OrderItem;
import com.zking.util.HibernateUtli;
public class OrderItemDaoImpl implements IOrderItemDaoImpl {
@Override
public Integer insertOrderItem(OrderItem orderItem) {
Session session = HibernateUtli.getCurrentSession();
Transaction transaction = session.beginTransaction();
Integer save = 0;
try {
save = (Integer) session.save(orderItem);
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
throw new RuntimeException("新增出現異常");
}
HibernateUtli.closeSession();
return save;
}
@Override
public void deleteOrderItem(OrderItem orderItem) {
Session session = HibernateUtli.getCurrentSession();
Transaction transaction = session.beginTransaction();
try {
session.delete(orderItem);
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
throw new RuntimeException("刪除出現異常");
}
HibernateUtli.closeSession();
}
@Override
public void editOrderItem(OrderItem orderItem) {
Session session = HibernateUtli.getCurrentSession();
Transaction transaction = session.beginTransaction();
try {
session.update(orderItem);
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
throw new RuntimeException("修改出現異常");
}
HibernateUtli.closeSession();
}
@Override
public OrderItem getOrderItem(OrderItem orderItem) {
Session session = HibernateUtli.getCurrentSession();
Transaction transaction = session.beginTransaction();
OrderItem t = null;
try {
t = session.get(OrderItem.class, orderItem.getOrder_item_id());
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
throw new RuntimeException("查詢出現異常");
}
HibernateUtli.closeSession();
return t;
}
@Override
public List<OrderItem> getOrderItemList(String str) {
Session session = HibernateUtli.getCurrentSession();
Transaction transaction = session.beginTransaction();
List<OrderItem> list = null;
try {
Criteria criteria = session.createCriteria(OrderItem.class);
list = criteria.list();
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
throw new RuntimeException("查詢出現異常");
}
HibernateUtli.closeSession();
return list;
}
}
package com.zking.entity;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class Order implements Serializable {
/**
* 2018年10月23日下午4:21:50
*/
private static final long serialVersionUID = 1575914611357638677L;
private Integer order_id;
private String order_no;
/**
* 在描述關係的時候,一定用含集合介面進行 一對多關係
*/
private Set<OrderItem> orderItem = new HashSet<>();
private Integer initorderItem = 0; //0 延遲載入 1 立即載入
public Integer getInitorderItem() {
return initorderItem;
}
public void setInitorderItem(Integer initorderItem) {
this.initorderItem = initorderItem;
}
public Set<OrderItem> getOrderItem() {
return orderItem;
}
public void setOrderItem(Set<OrderItem> orderItem) {
this.orderItem = orderItem;
}
@Override
public String toString() {
return "Order [order_id="+ order_id +",order_no="+ order_no +"]";
}
public Integer getOrder_id() {
return order_id;
}
public void setOrder_id(Integer order_id) {
this.order_id = order_id;
}
public String getOrder_no() {
return order_no;
}
public void setOrder_no(String order_no) {
this.order_no = order_no;
}
public Order() {
super();
}
public Order(Integer order_id,String order_no) {
super();
this.order_id = order_id;
this.order_no = order_no;
}
}
package com.zking.entity;
import java.io.Serializable;
public class OrderItem implements Serializable {
/**
* 2018年10月23日下午4:33:58
*/
private static final long serialVersionUID = 2468758266675428160L;
private Integer order_item_id;
private Integer product_id;
private Integer quantity;
private Integer oid;
private Order order;
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
@Override
public String toString() {
return "OrderItem [order_item_id="+ order_item_id +",product_id="+ product_id +",quantity="+ quantity +",oid="+ oid +"]";
}
public Integer getOrder_item_id() {
return order_item_id;
}
public void setOrder_item_id(Integer order_item_id) {
this.order_item_id = order_item_id;
}
public Integer getProduct_id() {
return product_id;
}
public void setProduct_id(Integer product_id) {
this.product_id = product_id;
}
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
this.quantity = quantity;
}
public Integer getOid() {
return oid;
}
public void setOid(Integer oid) {
this.oid = oid;
}
public OrderItem() {
super();
}
public OrderItem(Integer order_item_id,Integer product_id,Integer quantity,Integer oid) {
super();
this.order_item_id = order_item_id;
this.product_id = product_id;
this.quantity = quantity;
this.oid = oid;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!--
級聯查詢原理:
session.get(Order.class, 2);
select * from t_hibernate_order where order_id = ?(2)
2 P2 模擬查出來的資料
Order o = lass.forName("com.zking.entity.Order").newInstance(); 反射例項化
o.setorder_id(2).... 反射賦值
通過one-to-many中的class屬性找到對應的對映檔案
select * from t_hibernate_order_item where oid = ?(2)
查出來的資料
ResultSet rs
com.zking.entity.Order
原理是mvc EntityBaseDao,最後獲取到有值得list集合 -> orderItem
o.setOrderItem(orderItem)
-->
<class name="com.zking.entity.Order" table="t_hibernate_order">
<id name="order_id" type="java.lang.Integer" column="order_id">
<generator class="increment" />
</id>
<property name="order_no" type="java.lang.String" column="order_no"></property>
<!--
cascade:配置級聯關係
inverse:反方,是否將關聯關係交給對方控制
lazy="false":立即載入,預設延遲載入
-->
<set name="orderItem" cascade="save-update" inverse="false" >
<!-- 配置外來鍵欄位 -->
<key column="oid"></key>
<!-- 配置外來鍵關聯的類(表) -->
<one-to-many class="com.zking.entity.OrderItem"/>
</set>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.zking.entity.OrderItem" table="t_hibernate_order_item">
<id name="order_item_id" type="java.lang.Integer" column="order_item_id">
<generator class="increment" />
</id>
<property name="product_id" type="java.lang.Integer" column="product_id"></property>
<property name="quantity" type="java.lang.Integer" column="quantity"></property>
<property name="oid" type="java.lang.Integer" column="oid" insert="false" update="false"></property>
<!-- 會報錯 -->
<many-to-one name="order" class="com.zking.entity.Order" column="oid"></many-to-one>
</class>
</hibernate-mapping>
package com.zking.test;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import com.zking.dao.daoImpl.OrderDaoImpl;
import com.zking.entity.Order;
import com.zking.entity.OrderItem;
public class OrderDAOTest {
private OrderDaoImpl orderDao = null;
private Order order = null;
@Before
public void setUp() throws Exception {
orderDao = new OrderDaoImpl();
order = new Order();
}
/**
* 提交含有六個訂單項的一個訂單
*
* 2018年10月23日下午7:32:48
*/
@Test
public void testOrderAdd() {
OrderItem orderItem = null;
order.setOrder_no("P2");
for (int i = 1; i < 7; i++) {
orderItem = new OrderItem();
orderItem.setProduct_id(i);
orderItem.setQuantity(i);
order.getOrderItem().add(orderItem);
orderItem.setOrder(order);
}
this.orderDao.insertOrder(order);
}
@Test
public void testDel() {
order.setOrder_id(2);
/**
* 聯表刪除解決方案:
* 1.cascade="all" 設定為all,不推薦直接填寫delete
* 2.在dao層的刪除方法中先迴圈刪除所有外來鍵,再刪主鍵
*/
this.orderDao.deleteOrder(order);
}
@Test
public void testget() {
order.setOrder_id(2);
order.setInitorderItem(1);
order = this.orderDao.getOrder(order);
System.out.println(order);
/**
* Lazy=true介紹 查單個時存在問題 :當要真正用到查詢物件時候,session已經關閉
* 不存在初始化代理
* could not initialize proxy(代理) - no Session
* 懶載入(延遲載入)問題:
* 將查詢的oid(object id)儲存到session的代理proxy中當要真正用到查詢物件時候,再去執行SQL
* 解決問題:
* 強制立即載入:lazy="false":立即載入,預設延遲載入
*/
System.out.println(order.getOrderItem().size());
}
@Test
public void testgetList() {
List<Order> orderList = this.orderDao.getOrderList("");
/**
*Lazy=false介紹 查所有時存在問題 : 效能低
*/
for (Order order : orderList) {
System.out.println(order);
System.out.println(order.getOrderItem().size());
}
}
}
package com.zking.test;
import org.junit.Before;
import org.junit.Test;
import com.zking.dao.daoImpl.OrderItemDaoImpl;
import com.zking.entity.Order;
import com.zking.entity.OrderItem;
public class OrderItemDAOTest {
private OrderItemDaoImpl orderItemDao = null;
private Order order = null;
@Before
public void setUp() throws Exception {
orderItemDao = new OrderItemDaoImpl();
order = new Order();
}
@Test
public void testOrderItemAdd() {
OrderItem orderItem = new OrderItem();
order.setOrder_id(1);
orderItem.setOrder(order);
orderItem.setProduct_id(12);
orderItem.setQuantity(55);
// Repeated column in mapping for entity: com.zking.entity.OrderItem column: oid (should be mapped with insert="false" update="false")
// 實體對映中的重複列:com.zking.entity。OrderItem列:oid(應該用insert="false" update="false"進行對映)
this.orderItemDao.insertOrderItem(orderItem);
}
}