Hhibernateu关联关系第一次
今天上午我们老师的陪伴下练习一下Hibernate种尤为重要的一部分(关联关系)
级联关系类图:
在这个案例中我们使用一个部门可以有多个员工及(员工——部门表)来映射实体间的微妙关系
首先回忆在SqlServer中我们能想起来的关系
one:一
to:对应关系
money:多
1)1——>1 一对一 单项关联关系(one-to-one)
2)1——>n 一对多单项关联关系(one-to-money)
3)n——>1 多对一单项关联关系(money-to-one)
4)1<——>n 一对多的双向关联关系 (one-to-money)
5)1<——>n 一对多的双向自身关联关系(one-to-money)
基本上就这几种基本的关系其中4由于2和3也已经做了对应关系所以可以做双向关联
至于第五个就有的玩了,写过易买网或者树状菜单的都知道一张表实现连级连动他的好处是可以无限分类第5类一般出现在树形的组织结构中。至于表之间的关系介绍到 这了
下面开始分析类图
第一组图:
在员工(实体)中植入部门的一个实体——>多个员工对应一个部门
第二组图:
在部门(实体)中植入员工的Set集合——>一个部门可以有多个员工
注意(实体)二字因为Hibernate可以是面向对象的编程尽管那些HQL长的像SQL但是还是有一定的差别的,在这里重述一下官网推荐使用 select开头的查询语句
-------------------------------------------------------------------开发第一站-------------------------------------------------------
起步式:
在我们的分层架构下创建entity层
本次案例使用这个实体类和映射文件来操作
环境:ideat和oracle(已经在oracle中创建好了名称为y2166的用户并且等待hibernate自动创建表结构)
(Dept)
import java.util.HashSet; import java.util.Set; public class Dept { private Integer deptno; private String deptname; private Set<Emp> emps=new HashSet<Emp>(); public Set<Emp> getEmps() { return emps; }
(Emp)
public class Emp { private Integer empno; private String empname; private Dept dept;
(Dept.hbbm.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.happy.day07.entity"> <class name="Dept" table="Dept" schema="y2166" dynamic-update="true" > <id name="deptno" column="deptno"> <generator class="native"/> </id> <property name="deptname"/> <!--导航属性--> <set name="emps" cascade="save-update" order-by="empno desc" inverse="true"> <key column="deptno"></key> <one-to-many class="Emp" ></one-to-many> </set> </class> </hibernate-mapping>
(Emp.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.happy.day07.entity"> <class name="Emp" table="Emp" schema="y2166" > <id name="empno" column="empno"> <generator class="native"/> </id> <property name="empname"/> <many-to-one name="dept" class="Dept" column="deptno" lazy="false" ></many-to-one> </class> </hibernate-mapping>
(HibeernateUtil工具类)本次案例全站使用自定义的工具类..初学者的福利
package cn.happy.day07.util; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; public class HibernateUtil { //线程变量 get set static ThreadLocal<Session> tl=new ThreadLocal<Session>(); //有SeesionFactory static Configuration cfg=null; static SessionFactory sessionFactory; static Transaction tx; static { cfg=new Configuration().configure("hibernatethree.cfg.xml"); sessionFactory=cfg.buildSessionFactory(); } //01.获取连接 public static Session getSession(){ //01.从线程变量中尝试获取 Session session = tl.get(); if(session==null){ //用户第一次获取连接,发现线程变量中没有session创建一个,并放入线程变量 session=sessionFactory.openSession(); tl.set(session); } return session; } //02.释放连接 public static void close(){ Session session = tl.get(); if(session!=null){ //线程变量set成null tl.set(null); session.close(); } } }
以上案例都是已经经过测试的完整版如果有想做测试的请谨慎参考可能会影响实验结果
----------------------------------------------------------------------------------------------开始办----------------------------------------------------------------------
1.开发案例一:
关于映射文件中的属性会在后面详解
需求:关联查询,多对一关联关系
分析:
多个员工对用一个部门,所以我们在员工表中植入单个部门对象
private Dept dept;
注意一定要做get和set因为底层还是用到了set方法赋值的
因为是从多的一方像一的一方所以在Emp映射文件中如下:
<many-to-one name="dept" class="Dept" column="deptno" lazy="false" ></many-to-one>
name的属性是Dept类中dept字段class是类的全路径类型column是当前表Dept类中的属性
注意这里一个知识点
tip:通过实体类的构建我们发现并没有在Emp类中植入dept表的deptno属性,这是我们可以把deptno,deptname,统一看成是一个Dept实体
通过Class的属性Hibernate通过set访问器自动寻址deptno的尽管如次当我们单侧成功的时候依然还是发现在数据底层数据表中的Ep表中生成关系字段deptno
数据库截图:
测试方法
//关联查询 多对一单项关联1 @Test public void testmoneytonoebydouble(){ //工具类 Session session = HibernateUtil.getSession(); //提供一个员工的编号 Emp load = session.load(Emp.class, 1); System.out.println(load.getEmpname()); //隶属的部门 System.out.println(load.getDept().getDeptname()); }
结果:
使用ideat在空控制台打印输出结果
2.开发案例二:
需求:使用级联保存部门的同时保存员工
分析:使用导航属性在部门中添加员工更改映射文件的属性
<!--导航属性--> <set name="emps" cascade="save-update" order-by="empno desc" inverse="true"> <key column="deptno"></key> <one-to-many class="Emp" ></one-to-many> </set>
cascade="save-update"
注意如果不这样写在保存的时候会报一个错误
object references an unsaved transient instance - save the transient instance before flushing: cn.happy.day07.entity.Emp
原因就是没有开启连及(cascade)
测试方法
//保存部门的同时保存员工2 @Test public void savedeptandEmp(){ Session session = HibernateUtil.getSession(); Transaction tx=session.beginTransaction(); Dept dept=new Dept(); dept.setDeptname("测试部1"); Emp emp=new Emp(); emp.setEmpname("小军1"); dept.getEmps().add(emp); session.save(dept); tx.commit(); }
结果:
3.开发案例三:
需求:按照指定的部门对象,查询相关的emp对象
分析:一对多在部门中植入员工Emp对象
private Set<Emp> emps=new HashSet<Emp>();
<!--导航属性--> <set name="emps" cascade="save-update" order-by="empno desc" inverse="true"> <key column="deptno"></key> <one-to-many class="Emp" ></one-to-many> </set>
使用Set无序集合关于Set集合使用案例:
package cn.happy.day08; /** * Created by CY on 2017/12/28. */ public class Dog { private Integer dogage; private String dogname; @Override public int hashCode() { int result=17; result =result * 31+dogage; System.out.println(result+"1"); result =result * 31+dogname.hashCode(); System.out.println(result+"2"); return result; } @Override public boolean equals(Object obj) { Dog dog= (Dog)obj; if (this.getDogname().equals(dog.getDogname())){ return true; } return false; } public Integer getDogage() { return dogage; } public void setDogage(Integer dogage) { this.dogage = dogage; } public String getDogname() { return dogname; } public void setDogname(String dogname) { this.dogname = dogname; } }
简单的配置就好了记住其中的属性
s.k.o/n.c.c
测试方法:
@Test //按照指定的部门对象,查询相关的emp对象 public void t3() { Session session = HibernateUtil.getSession(); String hql = "from Emp e where e.dept.deptno=1"; Query query = session.createQuery(hql); List<Emp> list = query.list(); for (Emp item : list) { System.out.println(item.getEmpname()); } session.close(); }
结果:
4.开发案例四
需求:修改员工的同时修改部门 使用连及 caseode和inversit
分析: 前面我们已经分别在两个配置文件中添加相互映射所以我们直接构建实体并绑定关系来警醒修改
@Test public void updatedept(){ Session session = HibernateUtil.getSession(); Transaction tx=session.beginTransaction(); Dept dept=new Dept(); dept.setDeptno(2); dept.setDeptname("小买部"); Emp emp=new Emp(); emp.setEmpno(1); emp.setEmpname("小贱贱"); dept.getEmps().add(emp); session.saveOrUpdate(dept); tx.commit(); }
结果:
5.开发案例五
需求:一对多双向关联(两种方法双向遍历)
分析:在配置前提的情况下分别使用HQL语句和 session.get方法
测试类:
@Test public void onetomoneydouble(){ //检索部门的同时检索出员工 String hql="from Dept"; Session session = HibernateUtil.getSession(); Query query = session.createQuery(hql); List<Dept> list = query.list(); for (Dept item:list) { System.out.println(item.getDeptname()); for (Emp it:item.getEmps()) { System.out.println(it.getEmpname()); } } //检索出员工的同时检索出部门 Emp emp = session.get(Emp.class, 1); System.out.println(emp.getDept().getDeptname()+"HH"); }
结果:
INFO: HHH000397: Using ASTQueryTranslatorFactory Hibernate: /* from Dept */ select dept0_.deptno as deptno1_0_, dept0_.deptname as deptname2_0_ from y2166.Dept dept0_ 测试部2 Hibernate: select emps0_.deptno as deptno3_1_0_, emps0_.empno as empno1_1_0_, emps0_.empno as empno1_1_1_, emps0_.empname as empname2_1_1_, emps0_.deptno as deptno3_1_1_ from y2166.Emp emps0_ where emps0_.deptno=? order by emps0_.empno desc 测试部1 Hibernate: select emps0_.deptno as deptno3_1_0_, emps0_.empno as empno1_1_0_, emps0_.empno as empno1_1_1_, emps0_.empname as empname2_1_1_, emps0_.deptno as deptno3_1_1_ from y2166.Emp emps0_ where emps0_.deptno=? order by emps0_.empno desc 小军1 开发部 Hibernate: select emps0_.deptno as deptno3_1_0_, emps0_.empno as empno1_1_0_, emps0_.empno as empno1_1_1_, emps0_.empname as empname2_1_1_, emps0_.deptno as deptno3_1_1_ from y2166.Emp emps0_ where emps0_.deptno=? order by emps0_.empno desc 小明 小买部1 Hibernate: select emps0_.deptno as deptno3_1_0_, emps0_.empno as empno1_1_0_, emps0_.empno as empno1_1_1_, emps0_.empname as empname2_1_1_, emps0_.deptno as deptno3_1_1_ from y2166.Emp emps0_ where emps0_.deptno=? order by emps0_.empno desc 测试部 Hibernate: select emps0_.deptno as deptno3_1_0_, emps0_.empno as empno1_1_0_, emps0_.empno as empno1_1_1_, emps0_.empname as empname2_1_1_, emps0_.deptno as deptno3_1_1_ from y2166.Emp emps0_ where emps0_.deptno=? order by emps0_.empno desc 小军 开发部HH
6.属性介绍:
cascade属性
问题:如何实现添加部门的同时自动添加员工?
解析:可以使用cascade(级联)方式
Cascade取值:
None,save-update,delete和all
none:当Session操纵当前对象时,忽略其他关联的对象。它是cascade属性的默认值.
Save-update:当通过Session的save()、update()及saveOrUpdate()方法来保存或更新当前对象时,级联保存所有关联的新建的瞬时状态的对象,并且级联更新所有关联的游离状态的对象。
Delete:
当通过Session的delete()方法删除当前对象时,会级联删除所有关联的对象。
当通过Session的delete()方法删除当前对象时,会级联删除所有关联的对象。
All:
包含save-update,delete的行为。
注意点:级联也就是说当我们保存持久化对象A的时候自动帮我们保存持久化对象B。
2017年12月28日15点55分测试