[TOC]java
一对多
表之间关系
一对多sql
- 一个部门有多个员工,一个员工只能属于某一个部门
- 一个班级有多个学生,一个学生只能属于一个班级
多对多数据库
- 一个老师教多个学生,一个学生能够被多个老师教
- 一个学生能够先择多门课程,一门课程能够被多个学生选择
- 一个用户能够选择多个角色,一个角色也能够被多个用户选择
一对一session
- 一个公司只能对应一个注册地址
表之间关系建表原则
一对多 在多的一方建立一个外键,指向一的一方的主键 多对多 建立一个中间表,中间表至少有两个字段,分别做为外键指向多对多双方的主键 一对一 惟一外键对应 主键对应app
一对多关系配置
创建表
建立表的 hbm.xml文件时,有外键可不建立列的映射dom
主表为客户(Customer),从表为联系人(Linkman)ide
销售联系人(linkman),一个联系人只能属于某一个客户 工具
CREATE TABLE `linkman` ( `link_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)', `link_name` varchar(16) DEFAULT NULL COMMENT '联系人姓名', `link_cust_id` bigint(32) NOT NULL COMMENT '客户id', `link_gender` char(1) DEFAULT NULL COMMENT '联系人性别', `link_phone` varchar(16) DEFAULT NULL COMMENT '联系人办公电话', `link_mobile` varchar(16) DEFAULT NULL COMMENT '联系人手机', `link_email` varchar(64) DEFAULT NULL COMMENT '联系人邮箱', `link_qq` varchar(16) DEFAULT NULL COMMENT '联系人qq', `link_position` varchar(16) DEFAULT NULL COMMENT '联系人职位', `link_memo` varchar(512) DEFAULT NULL COMMENT '联系人备注', PRIMARY KEY (`link_id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
客户(customer),一个客户能够有多个联系人 测试
CREATE TABLE `customer` ( `cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)', `cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)', `cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源', `cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业', `cust_level` varchar(32) DEFAULT NULL COMMENT '客户级别', `cust_phone` varchar(64) DEFAULT NULL COMMENT '固定电话', `cust_mobile` varchar(16) DEFAULT NULL COMMENT '移动电话', PRIMARY KEY (`cust_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
关系图
创建ORM
实体类与数据库中创建字段 与 关系
Customer 实体类(一个客户能够有多个联系人)
package com.myxq.domain; import lombok.Getter; import lombok.Setter; import java.util.HashSet; import java.util.Set; @Getter@Setter public class Customer { private Long cust_id; private String cust_name; private String cust_source; private String cust_industry; private String cust_level; private String cust_phone; private String cust_mobile; //创建一个客户能够有多个联系人 //放置多的一方的集合,hibernate默认使用的是Set集合 //若是使用List的话,它要对List进行排列,在表中要多建这一列,用来排序 //通常使用的都是Set集合 //如今是双向关联,从客户能查联系人,从联系人也能查客户 private Set<Linkman> linkmens = new HashSet<>(); @Override public String toString() { return "Customer{" + "cust_id=" + cust_id + ", cust_name='" + cust_name + '\'' + ", cust_source='" + cust_source + '\'' + ", cust_industry='" + cust_industry + '\'' + ", cust_level='" + cust_level + '\'' + ", cust_phone='" + cust_phone + '\'' + ", cust_mobile='" + cust_mobile + '\'' + '}'; } }
Linkman 实体类(一个联系人只能属于一个客户)
package com.myxq.domain; import lombok.Getter; import lombok.Setter; @Getter@Setter public class Linkman { private Long link_id; private String link_name; private String link_gender; private String link_phone; private String link_mobile; private String link_email; private String link_qq; private String link_position; private String link_memo; private String link_cust_id; //一个联系人只对应一个客户 private Customer customer; @Override public String toString() { return "Linkman{" + "link_id=" + link_id + ", link_name='" + link_name + '\'' + ", link_gender='" + link_gender + '\'' + ", link_phone='" + link_phone + '\'' + ", link_mobile='" + link_mobile + '\'' + ", link_email='" + link_email + '\'' + ", link_qq='" + link_qq + '\'' + ", link_position='" + link_position + '\'' + ", link_memo='" + link_memo + '\'' + ", link_cust_id='" + link_cust_id + '\'' + ", customer=" + customer + '}'; } }
添加配置文件
1.客户(Customer)实体类的配置文件fetch
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> <class name="com.myxq.domain.Customer" table="customer" > <!--创建类属性哪个是主键 还要跟数据库当中主键进行对象--> <id name="cust_id" column="cust_id" > <generator class="native"/> </id> <!--创建类中的普通属性与数据库当中的表字段的映射,关联--> <property name="cust_name" column="cust_name" /> <property name="cust_source" column="cust_source"/> <property name="cust_industry" column="cust_industry"/> <property name="cust_level" column="cust_level"/> <property name="cust_phone" column="cust_phone"/> <property name="cust_mobile" column="cust_mobile"/> <!--一对多--> <set name="linkmens" cascade="save-update,delete" inverse="true"><!--set属性名称--> <key column="link_cust_id"></key><!--外键--> <one-to-many class="com.myxq.domain.Linkman"></one-to-many> </set> </class> </hibernate-mapping>
2.联系人(LinkMan)实体类配置文件 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> <class name="com.myxq.domain.Linkman" table="linkman" > <!--创建类属性哪个是主键 还要跟数据库当中主键进行对象--> <!-- 设置主键与OID的对应关系 --> <id name="link_id" column="link_id" > <generator class="native"/> </id> <!--创建类中的普通属性与数据库当中的表字段的映射 注意:外键不用设置--> <property name="link_name" column="link_name" /> <property name="link_gender" column="link_gender"/> <property name="link_phone" column="link_phone"/> <property name="link_mobile" column="link_mobile"/> <property name="link_email" column="link_email"/> <property name="link_qq" column=" link_qq"/> <property name="link_position" column=" link_position"/> <property name="link_memo" column=" link_memo"/> <!-- many-to-one:配置多对一 name:一的一方对象属性名称 class:一的一方类的全路径 column:多的一方表的外键名称 --> <many-to-one name="customer" cascade="save-update" class="com.myxq.domain.Customer" column="link_cust_id"/> </class> </hibernate-mapping>
在hibernate.cfg.xml中的<session-factory>标签里,添加核心配置文件
<!--加载映射文件--> <mapping resource="com/myxq/domain/customer.hbm.xml" /> <mapping resource="com/myxq/domain/linkman.hbm.xml" /> <mapping resource="com/myxq/domain/role.hbm.xml" /> <mapping resource="com/myxq/domain/user.hbm.xml" />
引入工具类
HibernateUtil.java
package com.myxq.utils; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtil { public static final SessionFactory sessionFactory; static { //1.加载配置文件 Configuration configure = new Configuration().configure(); //configure.addResource("com/myxq/domain/Customer.hbm.xml"); //2.建立sessionFactory --JDBC 链接池 sessionFactory = configure.buildSessionFactory(); } public static Session openSession(){ Session session = sessionFactory.openSession(); return session; } public static Session getCurrentSession(){ Session session = sessionFactory.getCurrentSession(); return session; } }
编写测试类
级联操做
问题 在两张表创建一对多关系时,若是只保存一边的对象,就会发异常 示例
什么是级联
在操做一个对象的时候,是否会操做其关联的对象。
级联分类
级联保存或更新 级联删除
级联是有方向性
在操做一的一方,是否会操做多的一方 操做多的一方时, 是否会操做一的一方
级联保存或更新
级联保存
操做的主体是谁,就要在谁的映射配置文件当中进行配置 在开始配置的set当中添加一个新的属性cascade="save-update"
在多的一方添加级联
再去运行,就不会报异常,两条记录都会被添加 在一的一方添加级联
对象导航
两方若是都加了级联,这种咱们也称为双向导航 设置双向导航时,当对象存在关系时, 就会作出对应的操做
级联更新
级联删除
删除一边数据时,同时将另外一边的数据一并删除
不设置级联删除
默认:先把外键改成空,而后再删除
发送的SQL语句
设置级联删除
示例代码
配置文件
在双向级联的过程中,会产生一些多余的sql语句
缘由 当双向维护时,两都都维护了外键,当作更新操做时, 两边的外键都要去修改
解决办法
1.使用单向维护 有些地方仍是会有问题 2.一方放弃维护权 在一的一方放弃外键维护权 在配置文件当中添加一个inverse="false/true" true为放弃外键维护权,false为不放弃外键维护权
cascade与inverse
cascade控制有没有关联对象 inverse控制有没有外键 示例
lazy懒加载(默认值是proxy,不自动获取外键对象)
改为false,获取外键对象
在linkman.hbm.xml
<many-to-one name="customer" class="com.myxq.domain.Customer" column="link_cust_id" lazy="false"/>
级联保存或更新(解决 瞬时对象异常,只保存一边)
在customer.hbm.xml
<set name="linkmens" cascade="save-update,delete" inverse="true"> <!--set属性名称--> <key column="link_cust_id"></key><!--外键--> <one-to-many class="com.myxq.domain.Linkman"> </one-to-many> </set>
多对多
多对多关系配置
创建表
用户表,一个用户能够有多个角色
CREATE TABLE `user` ( `user_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '用户id', `user_code` varchar(32) NOT NULL COMMENT '用户帐号', `user_name` varchar(64) NOT NULL COMMENT '用户名称', `user_password` varchar(32) NOT NULL COMMENT '用户密码', `user_state` char(1) NOT NULL COMMENT '1:正常,0:暂停', PRIMARY KEY (`user_id`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
角色表,一个角色能够被多个用户选择
CREATE TABLE `role` ( `role_id` bigint(32) NOT NULL AUTO_INCREMENT, `role_name` varchar(32) NOT NULL COMMENT '角色名称', `role_memo` varchar(128) DEFAULT NULL COMMENT '备注', PRIMARY KEY (`role_id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
关系图
创建ORM
- 用户
- 角色
Role.java
import lombok.Getter; import lombok.Setter; import java.util.HashSet; import java.util.Set; @Setter@Getter public class Role { private Long role_id; private String role_name; private String role_memo; //角色下面的全部用户 private Set<User> users = new HashSet<>(); }
添加配置文件
用户
角色
在核心配置文件当中添加两个新配置
编写测试类
单向维护
双向维护
双向维护时,必需要有一方放弃外键维护 若是两边都有维护的话, 就会有重复的的记录,因为关系表是两个字段做为共同主键,不能有相同的记录 解决办法 一般都是让被动方放弃,用户选角色,角色为被动方
多对多的级联操做和一对多的级联操做是同样的
多对多的操做
关系的操做,只须要操做集合,就能够操做它们之间的关系 给用户添加一个新的角色
修改一个用户的角色
删除角色
查询方式
OID查询
什么是OID查询
- 根据对象的OID主键进行检索
OID查询方式
- get方法
- load方法
对象导航查询
什么是对象导航检索
- Hibernate根据一个已经查询到的对象,得到其关联的对象的一种查询方式
- 先查询到联系人,就能够经过联系人获取联系人所关联的客户对象
有点像级联查询
HQL
什么是HQL
- HQL查询:Hibernate Query Language,Hibernate的查询语言
- 是一种面向对象的方式的查询语言,语法相似SQL。
- 经过session.createQuery(),用于接收一个HQL进行查询方式。
- 注意:使用时,不能用*,对于表,要采用别名查询
查询
简单查询
别名查询
排序查询
条件查询
位置绑定:根据参数的位置进行绑定条件
名称绑定:把参数对应的值起一个名称 再去设置名称
投影查询
查询对象的某个或某些属性 单个属性
多个属性
查询多个属性,封装到对象当中 要在类中,提供构造方法
分页查询
统计查询
查询的结构只有一个
分组查询
多表查询
普通内链接
迫切内链接 经过hibernate将另外一个对象的数据,封装该对象中
在普通内链接inner join 后添加一个关键字fetch
QBC
什么是QBC
Query By Criteria,条件查询。是一种更加面向对象化的查询的方式。
查询
简单查询
排序查询
分页查询
条件查询
条件 = eq > gt > = ge < lt <= le <> ne like in and or
单个条件
多个条件
统计查询
离线条件查询
- 脱离Session,添加条件
- 能够在外部提早使用DetachedCriteria对象提交设置好条件
- 最后再绑定到session当中