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

来源:互联网 发布:赵子易扒皮知乎 编辑:程序博客网 时间:2024/05/22 14:17

在我们以前的数据库设计中,设计表就不是一件轻松的事情。多种事物之间往往都是有这样那样的关系的。那怎样设计表格,才能既将事情描述明白,又能使数据库设计的比较合理呢?那里我们提供了好多规范,好多约束来满足这些事情。在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

<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><!-- Generated 2016-7-21 10:48:09 by Hibernate Tools 3.5.0.Final --><hibernate-mapping>    <class name="cn.limbo.hibernate.entity.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>    </class></hibernate-mapping>
Order.hbm.xml

<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><!-- Generated 2016-7-21 10:48:09 by Hibernate Tools 3.5.0.Final --><hibernate-mapping package="cn.limbo.hibernate.entity">    <class name="Order" table="ORDERS">        <id name="OrderId" type="java.lang.Integer">            <column name="ORDER_ID" />            <generator class="native" />        </id>        <property name="OrderName" type="java.lang.String">            <column name="ORDER_NAME" />        </property>        <many-to-one name="customer" class="Customer" column="CUSTOMER_ID"></many-to-one>    </class></hibernate-mapping>
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;@Beforepublic 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();}@Afterpublic void destroy(){transaction.commit();session.close();sessionFactory.close();}@Testpublic 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语句//推荐先插入一的一端,在插入多的一端,提升效率}@Testpublic 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对象是一个代理对象!}@Testpublic 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);}@Testpublic 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对应的学生加载进来。

1 0
原创粉丝点击