Hibernate学习笔记----单向多对一

在我们以前的数据库设计中,设计表就不是一件轻松的事情。多种事物之间往往都是有这样那样的关系的。那怎样设计表格,才能既将事情描述明白,又能使数据库设计的比较合理呢?那里我们提供了好多规范,好多约束来满足这些事情。在hibernate中,通过对象来创建表,当然也需要有一些东西来维护各个对象之间的关系,以创建出合适的表。这个东西就是映射。通过映射,可以轻松的将对象间的关系表述的非常清楚明白。对象间关系搞明白了,数据库表自然也就出来了。那我们先看一下关联映射。关联映射就是将关联关系映射到数据库中,所谓的关联关系在对象模型中就是一个或多个引用。

        首先来看一下多对一。举个例子来说用户和组。一个组中有多个用户,一个用户只能属于一组。用户和组之间就是一个多对一的关系的。如下图

       这个关系我们要怎样维护呢?我们想象一下,假如在一的一端维护关系,即在group一端加一个字段userId来标识学生。那设计出来的表格存储数据是这个样子的。

                  

         不解释,直接看在多的一端维护关系    

          

        不用说,大家就知道在多的一端维护数据冗余要少的多。怎么来解释这个问题呢?大家想一下是多的记少的容易记,还是少的记多的容易记呢?举个例子员工和老板。你说是老板记员工比较容易还是员工记老板比较容易呢?很明显记少的比较容易啊,能维护二者的关系也能减少工作量。hibernate当然也是这么做的。看一下实体和配置文件。这里只显示部分代码。        这里面并没有体现出任何与一的一端有关联的字段。一对多的关联最后生成的表格与多对一是一样的。但是他们到底有什么区别呢?多对一的维护关系是多指向一的关系,有了此关系,在加载多的时候可以将一加载上来。即我们查询用户的时候,组也被查询出来了。而一对多的关系,是指在加载一的时候可以将多加载进来。即查询组的时候,用户也被查出来了。他们适用于不同的需求。

Customer.java

package cn.limbo.hibernate.entity;

public class Customer {
	
	private Integer customerId;
	private String customerName;
	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;
	}
}
Order.java

package cn.limbo.hibernate.entity;

public class Order {
	private Integer OrderId;
	private String OrderName;
	
	private Customer customer;

	public Integer getOrderId() {
		return OrderId;
	}

	public void setOrderId(Integer orderId) {
		OrderId = orderId;
	}

	public String getOrderName() {
		return OrderName;
	}

	public void setOrderName(String orderName) {
		OrderName = orderName;
	}

	public Customer getCustomer() {
		return customer;
	}

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





    
        
            
            
        
        
            
        
    

Order.hbm.xml





    
        
            
            
        
        
            
        
        
    

test.java

package cn.limbo.hibernate.entity;

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

public class Junit {
	
	private SessionFactory sessionFactory ;
	private Session session;
	private Transaction transaction;
	
	@Before
	public void init()
	{
		Configuration configuration = new Configuration().configure();
		ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
				.applySettings(configuration.getProperties()).build();
		sessionFactory = configuration.buildSessionFactory(serviceRegistry);
		session = sessionFactory.openSession();
		transaction = session.beginTransaction();
	}
	
	@After
	public void destroy()
	{
		transaction.commit();
		session.close();
		sessionFactory.close();
	}
	
	@Test
	public void testManyToOne()
	{
		Customer customer = new Customer();
		customer.setCustomerName("Limbo");
		
		Order order1 = new Order();
		order1.setOrderName("AA");
		
		Order order2 = new Order();
		order2.setOrderName("BB");
		
		//设定关联关系
		order1.setCustomer(customer);
		order2.setCustomer(customer);
		//执行save:现插入Customer,再插入Order,3条INSERT
		//先插入一的一端,在插入多的一端,只有INSERT语句
		
		session.save(order1);
		session.save(order2);
		session.save(customer);
		//先插入Order,再插入Customer,3条INSERT,2条UPDATE
		//先插入多的一端,在插入一的一端,会多处UPDATE语句
		//因为在插入多的一端的时候,无法确定1的一端的外键值,所以只能等一的一端插入后,在额外发送UPDATE语句
		//推荐先插入一的一端,在插入多的一端,提升效率
	}
	
	@Test
	public void testManyToOneGet()
	{
		//1.若查询多的一端的一个对象,则在默认情况下,致查询了多的一端的对象,而没有查询关联的一的那一端
		
		Order order = (Order) session.get(Order.class, 3);
		System.out.println(order.getOrderName());
		
		//2.在需要使用到关联的对象的时候,才发送相应的SQL语句
		Customer customer = order.getCustomer();
		System.out.println(customer);
		
		//3.在查询Customer对象时,由多的一端导航到一的一端时,
		//若此时session已经关闭,可能会发生LazyInitizationException
		
		//4.获取Order对象时,默认情况下,其关联的Customer对象是一个代理对象!
	}
	
	@Test
	public void testUpdate()
	{
		Order order = (Order) session.get(Order.class, 3);
		order.getCustomer().setCustomerName("AAAA");
	}
	
	public void testDelete()
	{
		//再不设定级联关系的情况下,且一这一端的对象有多的一端的对象在引用,不能直接删除一这一端的对象
		Customer customer = (Customer) session.get(Customer.class, 1);
		session.delete(customer);
	}
	@Test
	public void testComponent()
	{
		Worker worker = new Worker();
		Pay pay = new Pay();
		
		pay.setMonthlyPay(1000);
		pay.setYearlyPay(80000);
		pay.setVacationWithPay(5);
		
		worker.setWorkerName("AA");
		worker.setPay(pay);
		session.save(worker);
	}
}

        刚开始我们说过,不管是一对多还是多对一,都是在多的一端维护关系。从程序的执行状况来解释一下这样做的原因。若在一的一端维护关系,多的一端User并不知道Group的存在。所以在保存User的时候,关系字段groupId是为null的。如果将该关系字段设置为非空,则将无法保存数据。另外因为User不维护关系,Group维护关系,则在对Group进行操作时,Group就会发出多余的update语句,去维持Group与User的关系,这样加载Group的时候才会把该Group对应的学生加载进来。

你可能感兴趣的:(Hibernate)