目录
表关系分析
Hibernate框架实现了ORM的思想,将关系数据库中表的数据映射成对象,使开发人员把对数据库的操作转化成对对象的操作,Hibernate的关联映射主要包括多表的映射配置、数据的增加、删除等。
数据库中多表之间存在着三种关系,也就是系统设计中的三种实体,在数据库中,实体表之间的关系映射是采用外键来描述的,如下图所示
-
一对多
建表原则:在多的一方创建外键指向一的一方主键
-
多对多
建表原则:创建一个中间表,中间表中至少两个字段作为外键分别指向多对多双方的主键
-
一对一
建表原则
1)唯一外键对应,假设一对一中的任意一方为多,在多的一方创建外键指向一的一方主键,然后将外键设置为唯一
2)主键对应,一方的主键作为另一方的主键
数据库表能够描述的实体数据之间的关系,通过对象也可以进行描述,所谓的关联映射就是将关联关系映射到数据库里,在对象模型中就是一个或多个引用。在Hibernate中采用Java对象关系来描述数据表之间的关系,具体图如下:
一对多关联映射
-
数据库表
cst_customer表(一)
cst_linkman表(多) --lkm_cust_id
两表关系
-
实体类
Customer
package com.mark.domain;
import java.util.HashSet;
import java.util.Set;
public class Customer {
private Long cust_id;
private String cust_name;
private Long cust_user_id;
private Long cust_create_id;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_linkman;
private String cust_phone;
private String cust_mobile;
//set集合存放多个Linkman对象
private Set<Linkman> linkmans = new HashSet<Linkman>();
//get|set方法省略...
}
Linkman
package com.mark.domain;
public class Linkman {
private Long lkm_id;
private String lkm_name;
private Character lkm_gender;
private String lkm_phone;
private String lkm_mobile;
private String lkm_email;
private String lkm_qq;
private String lkm_position;
private String lkm_memo;
//存放一个客户对象
private Customer customer;
//get|set方法省略....
}
-
实体与表映射文件
Customer-cst_customer
核心配置
<!-- 配置多的一方关联对象 -->
<!-- set标签:* name属性:多的一方集合的属性名称 -->
<set name="linkmans">
<!-- key标签: * column属性:多的一方外键名称 -->
<key column="lkm_cust_id"></key>
<!-- one-to-many标签:* name属性:多的一方类全路径-->
<one-to-many class="com.mark.domain.Linkman"/>
</set>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 实体与表文件映射配置 -->
<hibernate-mapping package="com.mark.domain">
<class name="Customer" table="cst_customer">
<!-- 实体与主键映射 -->
<id name="cust_id" column="cust_id">
<!-- 主键生成策略 -->
<generator class="native"></generator>
</id>
<!-- 实体与表普通列映射 -->
<property name="cust_name" column="cust_name"></property>
<property name="cust_user_id" column="cust_user_id"></property>
<property name="cust_create_id" column="cust_create_id"></property>
<property name="cust_source" column="cust_source"></property>
<property name="cust_industry" column="cust_industry"></property>
<property name="cust_level" column="cust_level"></property>
<property name="cust_linkman" column="cust_linkman"></property>
<property name="cust_phone" column="cust_phone"></property>
<property name="cust_mobile" column="cust_mobile"></property>
<!-- 配置多的一方关联对象 -->
<!-- set标签:
* name属性:多的一方集合的属性名称 -->
<set name="linkmans">
<!-- key标签:
* column属性:多的一方外键名称 -->
<key column="lkm_cust_id"></key>
<!-- one-to-many标签:
* name属性:多的一方类全路径
-->
<one-to-many class="com.mark.domain.Linkman"/>
</set>
</class>
</hibernate-mapping>
Linkman-cst_linkman
核心配置
<!-- 配置一的一方关联对象 -->
<!-- many-to-one标签:
* name属性 :一的一方对象名
* class属性 :一的一方类全路径
* column属性 :外键名称
-->
<many-to-one name="customer" class="com.mark.domain.Customer" column="lkm_cust_id"/>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 实体与表文件映射配置 -->
<hibernate-mapping package="com.mark.domain">
<class name="Linkman" table="cst_linkman">
<!-- 实体与主键映射 -->
<id name="lkm_id" column="lkm_id">
<!-- 主键生成策略 -->
<generator class="native"></generator>
</id>
<!-- 实体与表普通列映射 -->
<property name="lkm_name" column="lkm_name"></property>
<property name="lkm_gender" column="lkm_gender"></property>
<property name="lkm_phone" column="lkm_phone"></property>
<property name="lkm_mobile" column="lkm_mobile"></property>
<property name="lkm_email" column="lkm_email"></property>
<property name="lkm_qq" column="lkm_qq"></property>
<property name="lkm_position" column="lkm_position"></property>
<property name="lkm_memo" column="lkm_memo"></property>
<!-- 配置一的一方关联对象 -->
<!-- many-to-one标签:
* name属性 :一的一方对象名
* class属性 :一的一方类全路径
* column属性 :外键名称
-->
<many-to-one name="customer" class="com.mark.domain.Customer" column="lkm_cust_id"></many-to-one>
</class>
</hibernate-mapping>
-
Hibernate主配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!-- Hibernate核心文件配置 -->
<hibernate-configuration>
<session-factory>
<!-- 5个必要数据连接配置 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///crm</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!--Hibernate方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 3个可选数据库操作配置 -->
<!--Hibernate显示SQL语句 -->
<property name="hibernate.show_sql">true</property>
<!--Hibernate格式化SQL语句 -->
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!--Hibernate加载映射 -->
<mapping resource="com/mark/domain/Customer.hbm.xml"/>
<mapping resource="com/mark/domain/Linkman.hbm.xml"/>
</session-factory>
</hibernate-configuration>
-
测试类
public class OneToMany {
@Test
public void test(){
//获取Session对象
Session session = HibernateUtil.openSession();
//获取事务对象
Transaction trans = session.beginTransaction();
/*Customer customer = new Customer(); //一
customer.setCust_name("菲尔米诺");*/
Customer customer = session.get(Customer.class, 11L);
Linkman man1 = new Linkman(); //多
man1.setLkm_name("kitty");
Linkman man2 = new Linkman(); //多
man2.setLkm_name("milly");
man1.setCustomer(customer);
man2.setCustomer(customer);
customer.getLinkmans().add(man1);
customer.getLinkmans().add(man2);
//将上述创建的瞬时对象转换成持久态对象
session.save(customer);
session.save(man1);
session.save(man2);
//开始事务
trans.commit();
//关闭session
session.close();
}
}
-
级联优化
级联是有方向性的,所谓的方向性是指,在保存一的一方级联多的一方和在保存多的一方级联一的一方
cascade属性(简化操作,少写代码)
一的一方和多的一方,两者二选一在set标签中加入cascade属性就可以实现级联操作
<!-- set标签:
* name属性 :多的一方集合的属性名称
* cascade属性 :save-update(级联保存更新)、delete(级联删除)、all(前两者之和)-->
inverse属性(优化性能,提高关系维护)
因为双向维护外键关系,而且持久态对象可以自动更新数据库,更新客户的时候会修改一次外键,更新联系人的时候同样也会修改一次外键,这样就会产生了多余的SQL
为了去除冗余的SQL,只需要将一方的外键维护权即可,也就是说关系不是双方维护了,只需要交给某一方去维护就可以了。通常我们都是交给多的一方去维护,因为多的一方才是维护关系的最好地方,例如
一个老师对应多个学生,一个学生对应一个老师,这是典型的一对多。那么一个老师如果要记住所有学生的名字很难,但是如果让每个学生记住老师的名字就会很简单,所以在一对多种,一的一方都会放弃外键的维护权(关系维护)
这个时候,如果想让一的一方放弃外键的维护权,只需要进行如下配置
<!-- set标签:
* name属性 :多的一方集合的属性名称
* inverse属性 : true(放弃)、false(默认,不放弃)-->