• 双向 1-n 与 双向 n-1 是全然同样的两种情形
  • 双向 1-n 须要在 1 的一端能够訪问 n 的一端, 反之依旧.
  • 域模型:从 Order 到 Customer 的多对一双向关联须要在Order 类中定义一个 Customer 属性, 而在 Customer 类中需定义存放 Order 对象的集合属性
    hibernate 双向 1-n(具体分析)
  • 关系数据模型:ORDERS 表中的 CUSTOMER_ID 參照 CUSTOMER 表的主键
    hibernate 双向 1-n(具体分析)
  • 注意:
当 Session 从数据库中载入 Java 集合时, 创建的是 Hibernate 内置集合类的实例, 因此在持久化类中定义集合属性时必须把属性声明为 Java 接口类型
Hibernate 的内置集合类具有集合代理功能, 支持延迟检索策略
其实, Hibernate 的内置集合类封装了 JDK 中的集合类, 这使得 Hibernate 可以对缓存中的集合对象进行脏检查, 依照集合对象的状态来同步更新数据库。


在定义集合属性时, 通常把它初始化为集合实现类的一个实例. 这样能够提高程序的健壮性, 避免应用程序訪问取值为 null 的集合的方法抛出 NullPointerException
hibernate 双向 1-n(具体分析)
  • Hibernate 使用 <set> 元素来映射 set 类型的属性
    hibernate 双向 1-n(具体分析)
  • set:hibernate 双向 1-n(具体分析)hibernate 双向 1-n(具体分析)
  • key:hibernate 双向 1-n(具体分析)hibernate 双向 1-n(具体分析)
  • one-to-many:hibernate 双向 1-n(具体分析)hibernate 双向 1-n(具体分析)
  • hibernate 双向 1-n(具体分析)
Customer.java
package com.atguigu.hibernate.entities.n21.both;

import java.util.HashSet;
import java.util.Set;

public class Customer {

	private Integer customerId;
	private String customerName;
	
	/*
	 * 1. 声明集合类型时, 需使用接口类型, 由于 hibernate 在获取
	 * 集合类型时, 返回的是 Hibernate 内置的集合类型, 而不是 JavaSE 一个标准的
	 * 集合实现. 
	 * 2. 须要把集合进行初始化, 能够防止发生空指针异常
	 */
	private Set<Order> orders = new HashSet<>();

	public Integer getCustomerId() {
		return customerId;
	}

	public void setCustomerId(Integer customerId) {
		this.customerId = customerId;
	}

	public String getCustomerName() {
		return customerName;
	}

	public void setCustomerName(String customerName) {
		this.customerName = customerName;
	}

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

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

}

Order.java
package com.atguigu.hibernate.entities.n21.both;

public class Order {
	
	private Integer orderId;
	private String orderName;
	
	private Customer customer;

	public Integer getOrderId() {
		return orderId;
	}

	public void setOrderId(Integer orderId) {
		this.orderId = orderId;
	}

	public String getOrderName() {
		return orderName;
	}

	public void setOrderName(String orderName) {
		this.orderName = orderName;
	}

	public Customer getCustomer() {
		return customer;
	}

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

Customer.hbm.xml

> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.atguigu.hibernate.entities.n21.both"> <class name="Customer" table="CUSTOMERS"> <id name="customerId" type="java.lang.Integer"> <column name="CUSTOMER_ID" /> <generator class="native" /> </id> <property name="customerName" type="java.lang.String"> <column name="CUSTOMER_NAME" /> </property> <!-- 映射 1 对多的那个集合属性 --> <!-- set: 映射 set 类型的属性, table: set 中的元素相应的记录放在哪一个数据表中. 该值须要和多对一的多的那个表的名字一致 --> <!-- inverse: 指定由哪一方来维护关联关系. 通常设置为 true, 以指定由多的一端来维护关联关系 --> <!-- cascade 设定级联操作. 开发时不建议设定该属性. 建议使用手工的方式来处理 --> <!-- order-by 在查询时对集合中的元素进行排序, order-by 中使用的是表的字段名, 而不是持久化类的属性名 --> <set name="orders" table="ORDERS" inverse="true" order-by="ORDER_NAME DESC"> <!-- 运行多的表中的外键列的名字 --> <key column="CUSTOMER_ID"></key> <!-- 指定映射类型 --> <one-to-many class="Order"/> </set> </class> </hibernate-mapping>


Order.hbm.xml

package com.atguigu.hibernate.entities.n21.both;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class HibernateTest {

	private SessionFactory sessionFactory;
	private Session session;
	private Transaction transaction;
	
	@Before
	public void init(){
		Configuration configuration = new Configuration().configure();
		ServiceRegistry serviceRegistry = 
				new ServiceRegistryBuilder().applySettings(configuration.getProperties())
				                            .buildServiceRegistry();
		sessionFactory = configuration.buildSessionFactory(serviceRegistry);
		
		session = sessionFactory.openSession();
		transaction = session.beginTransaction();
	}
	
	@After
	public void destroy(){
		transaction.commit();
		session.close();
		sessionFactory.close();
	}
	
	@Test
	public void testCascade(){
		Customer customer = (Customer) session.get(Customer.class, 3);
		customer.getOrders().clear();
	}
	
	@Test
	public void testDelete(){
		//在不设定级联关系的情况下, 且 1 这一端的对象有 n 的对象在引用, 不能直接删除 1 这一端的对象
		Customer customer = (Customer) session.get(Customer.class, 1);
		session.delete(customer); 
	}
	
	@Test
	public void testUpdat2(){
		Customer customer = (Customer) session.get(Customer.class, 1);
		customer.getOrders().iterator().next().setOrderName("GGG"); 
	}
	
	@Test
	public void testUpdate(){
		Order order = (Order) session.get(Order.class, 1);
		order.getCustomer().setCustomerName("AAA");
	}
	
	@Test
	public void testOne2ManyGet(){
		//1. 对 n 的一端的集合使用延迟载入
		Customer customer = (Customer) session.get(Customer.class, 7);
		System.out.println(customer.getCustomerName()); 
		//2. 返回的多的一端的集合时 Hibernate 内置的集合类型. 
		//该类型具有延迟载入和存放代理对象的功能. 
		System.out.println(customer.getOrders().getClass()); 
		
		//session.close();
		//3. 可能会抛出 LazyInitializationException 异常 
		
		System.out.println(customer.getOrders().size()); 
		
		//4. 再须要使用集合中元素的时候进行初始化. 
	}
	
	@Test
	public void testMany2OneGet(){
		//1. 若查询多的一端的一个对象, 则默认情况下, 仅仅查询了多的一端的对象. 而没有查询关联的
		//1 的那一端的对象!
		Order order = (Order) session.get(Order.class, 1);
		System.out.println(order.getOrderName()); 
		
		System.out.println(order.getCustomer().getClass().getName());
		
		session.close();
		
		//2. 在须要使用到关联的对象时, 才发送相应的 SQL 语句. 
		Customer customer = order.getCustomer();
		System.out.println(customer.getCustomerName()); 
		
		//3. 在查询 Customer 对象时, 由多的一端导航到 1 的一端时, 
		//若此时 session 已被关闭, 则默认情况下
		//会发生 LazyInitializationException 异常
		
		//4. 获取 Order 对象时, 默认情况下, 其关联的 Customer 对象是一个代理对象!
		
	}
	
	@Test
	public void testMany2OneSave(){
		Customer customer = new Customer();
		customer.setCustomerName("AA");
		
		Order order1 = new Order();
		order1.setOrderName("ORDER-1");
		
		Order order2 = new Order();
		order2.setOrderName("ORDER-2");
		
		//设定关联关系
		order1.setCustomer(customer);
		order2.setCustomer(customer);
		
		customer.getOrders().add(order1);
		customer.getOrders().add(order2);
		
		//运行  save 操作: 先插入 Customer, 再插入 Order, 3 条 INSERT, 2 条 UPDATE
		//由于 1 的一端和 n 的一端都维护关联关系. 所以会多出 UPDATE
		//能够在 1 的一端的 set 节点指定 inverse=true, 来使 1 的一端放弃维护关联关系!
		//建议设定 set 的 inverse=true, 建议先插入 1 的一端, 后插入多的一端
		//优点是不会多出 UPDATE 语句
		session.save(customer);
		
//		session.save(order1);
//		session.save(order2);
		
		//先插入 Order, 再插入 Cusomer, 3 条 INSERT, 4 条 UPDATE
//		session.save(order1);
//		session.save(order2);
//		
//		session.save(customer);
	}

}



相关文章:

  • 2022-02-28
  • 2021-06-20
  • 2021-07-18
  • 2022-12-23
  • 2021-10-05
  • 2022-12-23
  • 2021-08-17
  • 2021-10-16
猜你喜欢
  • 2021-06-29
  • 2022-02-09
  • 2021-10-03
  • 2022-02-19
  • 2021-11-30
相关资源
相似解决方案