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