目录
一、一对多和多对一
1.1 关系表达
1.1.1 表中关系的表达
1.1.2 实体中的表达
1.1.3 orm中配置的表达
Customer.hbm.xml中的配置
<?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="cn.itcast.bean">
<class name="Customer" table="customer">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="name" column="name"></property>
<property name="age" column="age"></property>
<set name="linkMen">
<key column="cid"></key>
<one-to-many class="LinkMan"/>
</set>
</class>
</hibernate-mapping>
Customer实体的配置
package cn.itcast.bean;
import java.util.HashSet;
import java.util.Set;
public class Customer {
public int id;
public String name;
public int age;
private Set<LinkMan> linkMen = new HashSet<LinkMan>();
public Set<LinkMan> getLinkMen() {
return linkMen;
}
public void setLinkMen(Set<LinkMan> linkMen) {
this.linkMen = linkMen;
}
}
一对多的关系中,实体中需要配置一个集合来映射多的一方,由于记录的不重复,所以用set集合,hbm.xml中用<set>节点来配置
name:属性中的名字
column:外键列名
class:对应的实体的类名
<set name="linkMen">
<key column="cid"></key>
<one-to-many class="LinkMan"/>
</set>
LinkMan.hbm.xml中的配置
<?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="cn.itcast.bean">
<class name="LinkMan" table="linkMan">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="name" column="name"></property>
<many-to-one name="customer" class="Customer" column="cid"></many-to-one>
</class>
</hibernate-mapping>
LinkMan实体的配置
package cn.itcast.bean;
public class LinkMan {
private int id;
private String name;
private Customer customer;
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
其中多对一的属性用 <many-to-one>节点来配置
name:属性的名字
class:实体的类名
column:外键列名
<many-to-one name="customer" class="Customer" column="cid"></many-to-one>
1.1.4 代码维护关系
package cn.itcast.one2many;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import cn.itcast.bean.Customer;
import cn.itcast.bean.LinkMan;
import cn.itcast.util.HibernateUtils;
public class Demo {
@Test
public void testOne2Many() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//两个实体对象
Customer c1 = new Customer();
c1.setName("百度");
LinkMan lm1 = new LinkMan();
lm1.setName("李彦宏");
LinkMan lm2 = new LinkMan();
lm2.setName("王玉龙");
//互相维护关系
lm1.setCustomer(c1);
lm2.setCustomer(c1);
c1.getLinkMen().add(lm1);
c1.getLinkMen().add(lm2);
//保存 持久化
session.save(c1);
session.save(lm1);
session.save(lm2);
tx.commit();
session.close();
}
}
输出的sql语句
1.2 级联操作
1.2.1 级联保存更新
可以看到,在上述的插入客户和联系人的过程中,每增加一个联系人就得调用session.save(lm)一下,当我们有更多的联系人的时候就得保存不止一次,为了能让hibernate自动的帮我们级联的保存更新联系人,我们可以设置我们的级联操作
cascade:级联操作
save-update:级联保存更新
delete:级联删除
all:save-update+delete
<set name="linkMen" cascade="save-update">
<key column="cid"></key>
<one-to-many class="LinkMan"/>
</set>
设置之后我们就可以省去下面的几行代码:
@Test
public void testOne2Many() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//两个实体对象
Customer c1 = new Customer();
c1.setName("百度");
LinkMan lm1 = new LinkMan();
lm1.setName("李彦宏");
LinkMan lm2 = new LinkMan();
lm2.setName("王玉龙");
//互相维护关系
lm1.setCustomer(c1);
lm2.setCustomer(c1);
c1.getLinkMen().add(lm1);
c1.getLinkMen().add(lm2);
//保存 持久化
session.save(c1);
// session.save(lm1);
// session.save(lm2);
tx.commit();
session.close();
}
1.2.2 级联删除
<set name="linkMen" cascade="delete">
<key column="cid"></key>
<one-to-many class="LinkMan"/>
</set>
当cascade的值为save-update时,我们进行删除
@Test
public void testOne2ManyDelete() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Customer c = session.get(Customer.class, 1);
session.delete(c);
tx.commit();
session.close();
}
实际上数据库并没有删除linkman的数据,只是把外键cid设置为null
当cascade的值为delete时,我们进行删除,所有相关的数据都会删除了
1.3 关系维护优化
可以看出,最后两条更新语句有点多余,按说插入语句完成后,cid是已经生成了,不需要最后两条sql语句来维护关系了。
出现这个问题的原因就是我们的两个实体都相互维护了关系,其实只要一方维护关系就行了,hibernate就能自动识别了,所以我们需要做一下优化。让其中一方放弃维护关系
inverse:(是否反转)配置关系是否维护,true:customer不维护关系;false(默认值):customer 维护关系
inverse属性是来做性能优化的,使得一方放弃维护关系,会减少sql语句的生成
原则:无论如何放弃,必须有一方来维护关系。
一对多关系中,一的一方放弃,多的一方不放弃,也必须一的一方放弃
<set name="linkMen" inverse="true" cascade="save-update">
<key column="cid"></key>
<one-to-many class="LinkMan"/>
</set>
代码修改
public void testOne2Many() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//两个实体对象
Customer c1 = new Customer();
c1.setName("百度");
LinkMan lm1 = new LinkMan();
lm1.setName("李彦宏");
LinkMan lm2 = new LinkMan();
lm2.setName("王玉龙");
//互相维护关系
lm1.setCustomer(c1);
lm2.setCustomer(c1);
//客户放弃维护关系(也就是一的一方放弃维护关系)
//c1.getLinkMen().add(lm1);
//c1.getLinkMen().add(lm2);
//保存 持久化
session.save(c1);
session.save(lm1);
session.save(lm2);
tx.commit();
session.close();
}
但是session得保存每个lm使得持久化,输出入下
但是有点扯淡啊,还得调用save。
二、多对多关系
2.1 关系表达
2.1.1 表中关系
2.1.2 实体中的表达
2.1.3 orm元数据中的表达
由于多对多的关系需要一个中间表来维护,所以我们配置的时候要引入一张中间表。
name:集合属性名
table:配置的中间表名
key
|-column:外键列名,别人引用我的外键列名
class:我与那个类是多对多关系
column:外键,我引用别人的外键
<set name="users" table="user_role" cascade="save-update">
<key column="role_id"></key>
<many-to-many class="User" column="user_id"></many-to-many>
</set>
2.2 代码实现
2.2.1 实体
package cn.itcast.bean;
import java.util.HashSet;
import java.util.Set;
public class User {
private int user_id;
private String user_name;
private Set<Role> roles = new HashSet<Role>();
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
public int getUser_id() {
return user_id;
}
public void setUser_id(int user_id) {
this.user_id = user_id;
}
public String getUser_name() {
return user_name;
}
public void setUser_name(String user_name) {
this.user_name = user_name;
}
}
public class Role {
private int role_id;
private String role_name;
private Set<User> users =new HashSet<User>();
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
public int getRole_id() {
return role_id;
}
public void setRole_id(int role_id) {
this.role_id = role_id;
}
public String getRole_name() {
return role_name;
}
public void setRole_name(String role_name) {
this.role_name = role_name;
}
}
2.2.2 hbm.xml中的配置
User.hbm.xml
<?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="cn.itcast.bean">
<class name="User" table="user">
<id name="user_id" column="user_id">
<generator class="native"></generator>
</id>
<property name="user_name" column="user_name"></property>
<!--
name:集合属性名
table:配置的中间表名
key
|-column:外键列名,别人引用我的外键列名
class:我与那个类是多对多关系
column:外键,我引用别人的外键
-->
<set name="roles" table="user_role" cascade="save-update">
<key column="user_id"></key>
<many-to-many class="Role" column="role_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
Role.hbm.xml
<?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="cn.itcast.bean">
<class name="Role" table="role">
<id name="role_id" column="role_id">
<generator class="native"></generator>
</id>
<property name="role_name" column="role_name"></property>
<!--
name:集合属性名
table:配置的中间表名
key
|-column:外键列名,别人引用我的外键列名
class:我与那个类是多对多关系
column:外键,我引用别人的外键
-->
<set name="users" table="user_role" cascade="save-update">
<key column="role_id"></key>
<many-to-many class="User" column="user_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
2.2.3 代码
@Test
public void testMany2Many() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
User u1 = new User();
u1.setUser_name("李四");
User u2 = new User();
u2.setUser_name("张三");
Role r1 = new Role();
r1.setRole_name("管理员");
Role r2 = new Role();
r2.setRole_name("财务");
u1.getRoles().add(r1);
u1.getRoles().add(r2);
u2.getRoles().add(r1);
u2.getRoles().add(r2);
session.save(u1);
session.save(u2);
session.save(r1);
session.save(r2);
tx.commit();
session.close();
}
本测试使用了User的级联更新属性
输出如下
三、总结
这次我们主要学习了一对多,多对多关系的实现,hibernate的初衷是从代码开始,让开发者不再关注数据库,直接写逻辑,这和EF的codefirst是一样的道理。