一.
在领域模型中, 类与类之间最普遍的关系就是关联关系.
在 UML 中, 关联是有方向的.二.
显然无法直接用 property 映射 customer 属性
Hibernate 使用 <many-to-one> 元素来映射多对一关联关系
<many-to-one> 元素来映射组成关系
name: 设定待映射的持久化类的属性的名字
column: 设定和持久化类的属性对应的表的外键
class:设定待映射的持久化类的属性的类型
三.
以 Customer 和 Order 为例: 一个用户能发出多个订单, 而一个订单只能属于一个客户.
从 Order 到 Customer 的关联是多对一关联; 而从 Customer 到 Order 是一对多关联
1.Order类
package cn.edu.sdut.hibernate.manytoone;
public class Order {
private int orderId;
private String orderName;
<span style="color:#ff0000;">private Customer customer;</span>
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public Order(String orderName, Customer customer) {
super();
this.orderName = orderName;
this.customer = customer;
}
public Order() {
super();
}
}
2.Customer类
package cn.edu.sdut.hibernate.manytoone;
public class Customer {
private int customerId;
private String customerName;
public int getCustomerId() {
return customerId;
}
public void setCustomerId(int customerId) {
this.customerId = customerId;
}
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
public Customer(String customerName) {
super();
this.customerName = customerName;
}
public Customer() {
super();
}
}
3.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-10-29 15:15:16 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="cn.edu.sdut.hibernate.manytoone.Customer" table="CUSTOMERS">
<id name="customerId" type="int">
<column name="CUSTOMER_ID" />
<generator class="native" />
</id>
<property name="customerName" type="java.lang.String">
<column name="CUSTOMER_NAME" />
</property>
</class>
</hibernate-mapping>
<?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-10-29 15:15:16 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="cn.edu.sdut.hibernate.manytoone.Order" <span style="color:#ff0000;">table="ORDERS"</span>><!-- table不能为order关键字 -->
<id name="orderId" type="int">
<column name="ORDER_ID" />
<generator class="native" />
</id>
<property name="orderName" type="java.lang.String">
<column name="ORDER_NAME" />
</property>
<span style="color:#ff0000;"> <many-to-one name="customer" class="cn.edu.sdut.hibernate.manytoone.Customer">
<column name="CUSTOMER_ID" /><!-- </span><span style="color: rgb(255, 0, 0); font-family: Arial, Helvetica, sans-serif;">CUSTOMER_ID代表customers表的主</span><span style="color:#ff0000;">键,也就是orders表的外键 -->
</many-to-one></span>
</class>
</hibernate-mapping>
5.hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 配置连接数据库的基本信息 -->
<property name="connection.username">root</property>
<property name="connection.password">csc</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql:///hibernate5</property>
<!-- 配置hibernate的基本信息 -->
<!-- hibernate 所使用的数据库方言 -->
<property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
<!-- 执行sql时是否在控制台上打印 -->
<property name="show_sql">true</property>
<!-- 是否对sql进行格式化 -->
<property name="format_sql">true</property>
<!-- 指定自动生成数据表的策略 -->
<property name="hbm2ddl.auto">update</property>
<!-- 指定session的delete方法会把对象的id置为null -->
<property name="hibernate.use_identifier_rollback">true</property>
<!-- 指定数据库的隔离级别 -->
<property name="connection.isolation">2</property>
<!-- 配置c3p0数据池 -->
<property name="hibernate.c3p0.max_size">100</property>
<property name="hibernate.c3p0.min_size">20</property>
<property name="hibernate.c3p0.acquire_increment">5</property>
<property name="hibernate.c3p0.timeout">2000</property>
<property name="hibernate.c3p0.idle_test_period">2000</property>
<property name="hibernate.c3p0.max_statements">10</property>
<!-- 设定JDBC的statment读取数据的时候每次在数据库中读取的记录的条数 -->
<property name="hibernate.jdbc.fetch_size">100</property>
<!-- 设定对数据进行批量操作,批次更新和批次插入的批次大小 -->
<property name="hibernate.jdbc.batch_size">30</property>
<!-- 指定关联的xxx.hbm.xml文件 -->
<mapping resource="cn/edu/sdut/hibernate/helloworld/News.hbm.xml"/>
<mapping resource="cn/edu/sdut/hibernate/manytoone/Customer.hbm.xml"/>
<mapping resource="cn/edu/sdut/hibernate/manytoone/Order.hbm.xml"/>
</session-factory>
</hibernate-configuration>
6.test类
package cn.edu.sdut.hibernate.manytoone;
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;
public class Test {
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();
}
@org.junit.Test
public void testSaveManyToOne(){
Customer customer = new Customer("aa");
Order order1 = new Order();
order1.setOrderName("11");
Order order2 = new Order();
order2.setOrderName("22");
//设定关联关系
order1.setCustomer(customer);
order2.setCustomer(customer);
//执行 save 操作: 先插入 Customer, 再插入 Order, 3 条 INSERT
//先插入 1 的一端, 再插入 n 的一端, 只有 INSERT 语句.
session.save(customer);
session.save(order1);
session.save(order2);
//先插入 Order, 再插入 Customer. 3 条 INSERT, 2 条 UPDATE
//先插入 n 的一端, 再插入 1 的一端, 会多出 UPDATE 语句!
//因为在插入多的一端时, 无法确定 1 的一端的外键值. 所以只能等 1 的一端插入后, 再额外发送 UPDATE 语句.
//推荐先插入 1 的一端, 后插入 n 的一端
session.save(order1);
session.save(order2);
session.save(customer);
}
@org.junit.Test
public void testGetManyToOne(){
//1. 若查询多的一端的一个对象, 则默认情况下, 只查询了多的一端的对象. 而没有查询关联的
//1 的那一端的对象!
Order order = (Order) session.get(Order.class, 1);
System.out.println(order.getOrderName());
System.out.println(order.getCustomer().getClass().getName());
//2. 在需要使用到关联的对象时, 才发送对应的 SQL 语句.
System.out.println(order.getCustomer().getCustomerName());
//3. 在查询 Customer 对象时, 由多的一端导航到 1 的一端时,
//若此时 session 已被关闭, 则默认情况下会发生 LazyInitializationException 异常
//4. 获取 Order 对象时, 默认情况下, 其关联的 Customer 对象是一个代理对象!
}
@org.junit.Test
public void testUpdateManyToOne(){
Order order = (Order) session.get(Order.class, 1);
//可以修改数据库中的数据
order.getCustomer().setCustomerName("1111");
}
@org.junit.Test
public void testDeleteManyToOne(){
//在不设定级联关系的情况下, 且 1 这一端的对象有 n 的对象在引用, 不能直接删除 1 这一端的对象
Customer customer = (Customer) session.get(Customer.class,6);
session.delete(customer);
}
@After
public void destory(){
transaction.commit();
session.close();
sessionFactory.close();
}
}