1、表与表之间关系
1、 一对多
(1)分类和商品关系,一个分类里面有多个商品,一个商品只能属于一个分类
(2)客户和联系人是一对多关系
- 客户:与公司有业务往来,百度、新浪、360
- 联系人:公司里面的员工,百度里面有很多员工,联系员工
** 公司和公司员工的关系
- 客户是一,联系人是多
- 一个客户里面有多个联系人,一个联系人只能属于一个客户
(3)一对多建表:通过外键建立关系
2 、多对多
(1)订单和商品关系,一个订单里面有多个商品,一个商品属于多个订单
(2)用户和角色多对多关系
- 用户:小王、小马、小宋
- 角色:总经理、秘书、司机、保安
** 比如小王可以 是总经理,可以是司机
** 比如小宋可以是司机,可以是秘书,可以保安
** 比如小马可以是 秘书,可以是总经理
- 一个用户里面可以有多个角色,一个角色里面可以有多个用户
(3)多对多建表:创建第三张表维护关系
3、 一对一
(1)在中国,一个男人只能有一个妻子,一个女人只能有一个丈夫2、Hibernate的一对多操作(重点)
1、一对多映射配置
以客户和联系人为例:客户是一,联系人是多
第一步 创建两个实体类,客户和联系人
第二步 让两个实体类之间互相表示
(1)在客户实体类里面表示多个联系人
- 一个客户里面有多个联系人,在客户实体类中表示多个联系人,一个客户有多个联系人hibernate中要求使用 集合表示多的数据,要求使用set集合,set是无序的且不能有重复元素
package cn.itcast.entity;
import java.util.HashSet;
public class Customer {
//客户id
private Integer cid;
//客户名称
private String custName;
//客户级别
private String custLevel;
//客户来源
private String custSource;
//联系电话
private String custPhone;
//手机
private String custMobile;
// 在客户实体类中表示多个联系人,一个客户有多个联系人
// hibernate中要求使用集合表示多的数据,要求使用set集合,set是无序的且不能有重复元素
private HashSet<LinkMan> setLinkMan = new HashSet<LinkMan>();
// 生成setlinkMan的get与set
public HashSet<LinkMan> getSetLinkMan() {
return setLinkMan;
}
public void setSetLinkMan(HashSet<LinkMan> setLinkMan) {
this.setLinkMan = setLinkMan;
}
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
public String getCustLevel() {
return custLevel;
}
public void setCustLevel(String custLevel) {
this.custLevel = custLevel;
}
public String getCustSource() {
return custSource;
}
public void setCustSource(String custSource) {
this.custSource = custSource;
}
public String getCustPhone() {
return custPhone;
}
public void setCustPhone(String custPhone) {
this.custPhone = custPhone;
}
public String getCustMobile() {
return custMobile;
}
public void setCustMobile(String custMobile) {
this.custMobile = custMobile;
}
}
(2)在联系人实体类里面表示所属客户
- 一个联系人只能属于一个客户,在联系人的实体类中创建客户对象
package cn.itcast.entity;
public class LinkMan {
private Integer lkm_id; // 联系人编号(主键)
private String lkm_name;// 联系人姓名
private String lkm_gender;// 联系人性别
private String lkm_phone;// 联系人办公电话
//在联系人人实体类里面表示所属客户,一个联系人只能属于一个客户
private Customer customer;
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Integer getLkm_id() {
return lkm_id;
}
public void setLkm_id(Integer lkm_id) {
this.lkm_id = lkm_id;
}
public String getLkm_name() {
return lkm_name;
}
public void setLkm_name(String lkm_name) {
this.lkm_name = lkm_name;
}
public String getLkm_gender() {
return lkm_gender;
}
public void setLkm_gender(String lkm_gender) {
this.lkm_gender = lkm_gender;
}
public String getLkm_phone() {
return lkm_phone;
}
public void setLkm_phone(String lkm_phone) {
this.lkm_phone = lkm_phone;
}
}
第三步 配置映射关系
(1)一般一个实体类对应一个映射文件
(2)把映射最基本配置完成
(3)在映射文件中,配置一对多关系
- 在客户映射文件中,表示所有联系人
具体配置文件:
<?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>
<!-- 1 配置类和表对应 class标签 name属性:实体类全路径 table属性:数据库表名称 -->
<class name="cn.itcast.entity.Customer" table="t_customer">
<id name="cid" column="cid">
<generator class="native"></generator>
</id>
<property name="custName" column="custName"></property>
<property name="custLevel" column="custLevel"></property>
<property name="custSource" column="custSource"></property>
<property name="custPhone" column="custPhone"></property>
<property name="custMobile" column="custMobile"></property>
<!-- 在客户映射文件中,表示所有联系人 使用set标签表示所有联系人 set标签里面有name属性: 属性值写在客户实体类里面表示联系人的set集合名称
inverse属性默认值:false不放弃关系维护 true表示放弃关系维护 -->
<set name="setLinkMan" inverse="true">
<!-- 一对多建表,有外键 hibernate机制:双向维护外键,在一和多那一方都配置外键 column属性值:外键名称 -->
<key column="clid"></key>
<!-- 客户所有的联系人,class里面写联系人实体类全路径 -->
<one-to-many class="cn.itcast.entity.LinkMan" />
</set>
</class>
</hibernate-mapping>
- 在联系人映射文件中,表示所属客户
<?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>
<!-- 1 配置类和表对应 class标签 name属性:实体类全路径 table属性:数据库表名称 -->
<class name="cn.itcast.entity.LinkMan" table="t_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>
<!-- 表示联系人所属客户 name属性:因为在联系人实体类使用customer对象表示,写customer名称 class属性:customer全路径
column属性:外键名称 -->
<!-- 一对多实体类配置 -->
<many-to-one name="customer" class="cn.itcast.entity.Customer"
column="clid"></many-to-one>
</class>
</hibernate-mapping>
第四步 创建核心配置文件,把映射文件引入到核心配置文件中
<?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-configuration>
<session-factory>
<!-- 第一部分: 配置数据库信息 必须的 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///hibernate_day03_Customer</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">Huang123</property>
<!-- 第二部分: 配置hibernate信息 可选的 -->
<!-- 输出底层sql语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 输出底层sql语句格式 -->
<property name="hibernate.format_sql">true</property>
<!-- hibernate帮创建表,需要配置之后 update: 如果已经有表,更新,如果没有,创建 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 配置数据库方言 在mysql里面实现分页 关键字 limit,只能使用mysql里面 在oracle数据库,实现分页rownum 让hibernate框架识别不同数据库的自己特有的语句 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!--配置本地线程绑定session -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 第三部分: 把映射文件放到核心配置文件中 必须的 -->
<mapping resource="com/hibernate_stu/entity/Customer/User.hbm.xml" />
<mapping resource="com/hibernate_stu/entity/Customer/User.hbm.xml" />
</session-factory>
</hibernate-configuration>
HibernateUtils类为(直接JavaApplication执行):
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
static Configuration cfg = null;
static SessionFactory sessionFactory = null;
//静态代码块实现
static {
//加载核心配置文件
cfg = new Configuration();
cfg.configure();
sessionFactory = cfg.buildSessionFactory();
}
//提供返回与本地线程绑定的session
public static Session getSessionObject(){
return sessionFactory.getCurrentSession();
}
//提供方法返回sessionFactory
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void main(String[] args) {
}
}
测试结果:在数据库建立表
3、一对多级联操作(重点)
级联操作
1、 级联保存
(1)添加一个客户,为这个客户添加多个联系人
2 、级联删除
(1)删除某一个客户,这个客户里面的所有的联系人也删除1、一对多级联保存
(2)添加客户,为这个客户添加一个联系人
复杂写法:
// 演示Hibernate级联保存,麻烦方式
@Test
public void testAddDemo1() {
Transaction tr = null;
Session session = null;
SessionFactory sessionFactory = null;
try {
sessionFactory = HibernateUtils.getSessionFactory();
session = sessionFactory.openSession();
tr = session.beginTransaction();
// 添加一个客户,并对客户进行级联保存
// 1.创建客户与联系人对象
Customer customer = new Customer();
customer.setCustName("百度");
customer.setCustLevel("vip");
customer.setCustSource("网络");
customer.setCustPhone("110");
customer.setCustMobile("119");
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("lucy");
linkMan.setLkm_gender("gender");
linkMan.setLkm_phone("911");
// 2.在客户中表示联系人,在联系人中表示客户,建立客户对象与联系人对象的关系
// 两个对象建立关系
// 2.1在客户中表示所有联系人,将联系人对象放到客户实体类对象的Set集合中
customer.getSetLinkMan().add(linkMan);
// 2.2将客户对象放到联系人中
linkMan.setCustomer(customer);
// 保存到数据库
session.save(customer);
session.save(linkMan);
tr.commit();
} catch (Exception e) {
tr.rollback();
e.printStackTrace();
} finally {
// session.close();
// sessionFactory.close();
}
}
添加到数据库:
(2)简化写法
- 一般根据客户添加联系人
第一步 在客户映射文件中进行配置
- 在客户映射文件里面set标签进行配置
<set name="setLinkMan" cascade="save-update">
<!-- 一对多建表,有外键 hibernate机制:双向维护外键,在一和多那一方都配置外键 column属性值:外键名称 -->
<key column="clid"></key>
<!-- 客户所有的联系人,class里面写联系人实体类全路径 -->
<one-to-many class="cn.itcast.entity.LinkMan" />
</set>
- 创建客户和联系人对象,只需要把联系人放到客户里面就可以了,最终只需要保存客户就可以了
//演示一对多级联保存
@Test
public void testAddDemo2() {
SessionFactory sessionFactory = null;
Sessionsession = null;
Transactiontx = null;
try{
//得到sessionFactory
sessionFactory =HibernateUtils.getSessionFactory();
//得到session
session= sessionFactory.openSession();
//开启事务
tx= session.beginTransaction();
//添加一个客户,为这个客户添加一个联系人
//1创建客户和联系人对象
Customercustomer = new Customer();
customer.setCustName("百度");
customer.setCustLevel("普通客户");
customer.setCustSource("网络");
customer.setCustPhone("110");
customer.setCustMobile("999");
LinkManlinkman = new LinkMan();
linkman.setLkm_name("小宏");
linkman.setLkm_gender("男");
linkman.setLkm_phone("911");
//2把联系人放到客户里面
customer.getSetLinkMan().add(linkman);
//3保存客户
session.save(customer);
//提交事务
tx.commit();
}catch(Exceptione) {
tx.rollback();
}finally{
session.close();
//sessionFactory不需要关闭
sessionFactory.close();
}
}
4、一对多级联删除
1 、删除某个客户,把客户里面所有的联系人删除
2、 具体实现
第一步 在客户映射文件set标签,进行配置
(1)使用属性cascade属性值 delete
<set name="setLinkMan" cascade="save-update,delete">
<!-- 一对多建表,有外键 hibernate机制:双向维护外键,在一和多那一方都配置外键 column属性值:外键名称 -->
<key column="clid"></key>
<!-- 客户所有的联系人,class里面写联系人实体类全路径 -->
<one-to-many class="cn.itcast.entity.LinkMan" />
</set>
第二步 在代码中直接删除客户
(1)根据id查询对象,调用session里面delete方法删除
3 、执行过程:
(1)根据id查询客户
(2)根据外键id值查询联系人
(3)把联系人外键设置为null
(4)删除联系人和客户
5、一对多修改操作(inverse属性)
1 、让lucy联系人所属客户不是传智播客,而是百度2 、inverse属性
(1)因为hibernate的机制是双向维护外键,在客户和联系人里面都需要维护外键,修改客户时候修改一次外键,修改联系人时候也修改一次外键,造成效率问题
(2)解决方式:让其中的一方不维护外键
- 一对多里面,让其中一方放弃外键维护(一的一方放弃维护外键)
-举例: 一个国家有总统,国家有很多人,总统不能认识国家所有人,国家所有人可以认识总统
(3)具体实现:
在放弃关系维护映射文件中,进行配置,在set标签上使用inverse属性
<!-- 在客户映射文件中,表示所有联系人 使用set标签表示所有联系人 set标签里面有name属性: 属性值写在客户实体类里面表示联系人的set集合名称
inverse属性默认值:false不放弃关系维护 true表示放弃关系维护 -->
<set name="setLinkMan" inverse="true">
<!-- 一对多建表,有外键 hibernate机制:双向维护外键,在一和多那一方都配置外键 column属性值:外键名称 -->
<key column="clid"></key>
<!-- 客户所有的联系人,class里面写联系人实体类全路径 -->
<one-to-many class="cn.itcast.entity.LinkMan" />
</set>
6、Hibernate多对多操作
1、多对多映射配置
以用户和角色为例演示
第一步 创建实体类,用户和角色
第二步 让两个实体类之间互相表示
(1)一个用户里面表示所有角色,使用set集合
(2)一个角色有多个用户,使用set集合
第三步 配置映射关系
(1)基本配置
(2)配置多对多关系
- 在用户里面表示所有角色,使用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>
<class name="com_hibernatestu.entity.User" table="t_user">
<id name="user_id" column="user_id">
<generator class="native"></generator>
</id>
<property name="user_name" column="user_name"></property>
<property name="user_password" column="user_password"></property>
<!-- 在用户中表示有多个角色,使用set标签 name属性:角色set集合名称 table属性:第三张表名称 -->
<!--级联保存操作 cascade="save-update" -->
<set name="roleSet" table="user_role" cascade="save-update,delete">
<!-- key里的column配置:当前的映射文件在第三张表的外键的名称 -->
<key column="userid"></key>
<!-- class是角色全路径,column是角色在第三张表的外键名称 -->
<many-to-many class="com_hibernatestu.entity.Role"
column="roleid"></many-to-many>
</set>
</class>
</hibernate-mapping>
- 在角色里面表示所有用户,使用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>
<class name="com_hibernatestu.entity.Role" table="t_role">
<id name="role_id" column="role_id">
<generator class="native"></generator>
</id>
<property name="role_name" column="role_name"></property>
<property name="role_memo" column="role_memo"></property>
<!-- 在角色中表示所有的用户也是使用set -->
<set name="userSet" table="user_role">
<key column="roleid"></key>
<many-to-many class="com_hibernatestu.entity.Role"
column="userid"></many-to-many>
</set>
</class>
</hibernate-mapping>
注意:在用户里面表示所有角色,在角色里面表示所有用户,容易弄混,下面是配置的对应关系
第四步 在核心配置文件中引入映射文件,实体类的全路径
7、多对多级联保存
根据用户保存角色
第一步 在用户配置文件中set标签进行配置,cascade值save-update
第二步 写代码实现
(1)创建用户和角色对象,把角色放到用户里面,最终保存用户就可以了
//演示多对多修级联保存
@Test
publicvoid testSave(){
SessionFactorysessionFactory = null;
Sessionsession = null;
Transactiontx = null;
try {
//得到sessionFactory
sessionFactory= HibernateUtils.getSessionFactory();
//得到session
session= sessionFactory.openSession();
//开启事务
tx= session.beginTransaction();
//添加两个用户,为每个用户添加两个角色
//1创建对象
Useruser1 = new User();
user1.setUser_name("lucy");
user1.setUser_password("123");
Useruser2 = new User();
user2.setUser_name("mary");
user2.setUser_password("456");
Role r1 = new Role();
r1.setRole_name("总经理");
r1.setRole_memo("总经理");
Role r2 = new Role();
r2.setRole_name("秘书");
r2.setRole_memo("秘书");
Role r3 = new Role();
r3.setRole_name("保安");
r3.setRole_memo("保安");
//2 建立关系,把角色放到用户里面
// user1 -- r1/r2
user1.getSetRole().add(r1);
user1.getSetRole().add(r2);
// user2 -- r2/r3
user2.getSetRole().add(r2);
user2.getSetRole().add(r3);
//3 保存用户
session.save(user1);
session.save(user2);
//提交事务
tx.commit();
}catch(Exception e) {
tx.rollback();
}finally{
session.close();
//sessionFactory不需要关闭
sessionFactory.close();
}
}
8、多对多级联删除
第二步 写代码实现
(1)创建用户和角色对象,把角色放到用户里面,最终保存用户就可以了
第一步 在set标签进行配置,cascade值delete
第二步 删除用户
9、维护第三张表关系
多对对的表关系中,一般是通过维护第三张表来维护表之间的关系
(1)创建用户和角色对象,把角色放到用户里面,最终保存用户就可以了
1 、用户和角色多对多关系,维护关系通过第三张表维护
2 、让某个用户有某个角色
第一步 根据id查询用户和角色
第二步 把角色放到用户里面
(1)把角色对象放到用户set集合
3 、让某个用户没有某个角色
第一步 根据id查询用户和角色
第二步 从用户里面把角色去掉
(1)从set集合里面把角色移除
第二步 写代码实现
(1)创建用户和角色对象,把角色放到用户里面,最终保存用户就可以了
public class TestAdd {
@Test
//多对多级联添加
//1.在用户配置文件中set标签进行配置,cascade=“save-update”
//2.创建用户和角色对象,将角色放到用户中
//3.保存用户
public void testAddDemo1() {
Transaction tr = null;
Session session = null;
SessionFactory sessionFactory = null;
try {
sessionFactory=HibernateUtils.getSessionFactory();
session = sessionFactory.openSession();
tr = session.beginTransaction();
//添加两个用户,为,每个用户添加两个角色
User user1= new User();
user1.setUser_name("小陈");
user1.setUser_password("123");
User user2 = new User();
user2.setUser_name("小董");
user2.setUser_password("465");
Role role1=new Role();
role1.setRole_memo("保洁");
role1.setRole_name("保洁");
Role role2=new Role();
role2.setRole_memo("技术员");
role2.setRole_name("技术员");
Role role3=new Role();
role3.setRole_memo("管理");
role3.setRole_name("管理");
//建立角色与用户的关系,将角色放到用户中
//user1---role1 and role2
user1.getRoleSet().add(role1);
user1.getRoleSet().add(role2);
//User2---role2 and role3
user2.getRoleSet().add(role2);
user2.getRoleSet().add(role3);
//保存用户
session.save(user1);
session.save(user2);
tr.commit();
} catch (Exception e) {
tr.rollback();
e.printStackTrace();
} finally {
session.close();
sessionFactory.close();
}
}
}
本章小结:
1、 列表功能实现
2、 表与表之间关系回顾
(1)一对多(客户和联系人)
(2)多对多(用户和角色)
2 、hibernate一对多操作
(1)一对多映射配置
(2)一对多级联保存
(3)一对多级联删除
(4)inverse属性
3、 hibernate多对多操作
(1)多对多映射配置
(2)多对多级联保存(重点)
(3)多对多级联删除
(4)维护第三张表