首先,我们知道hibernate是一个ORM框架,ORM的全称是(Object Relational Mapping),既对象关系映射,那么hibernate有几种对象关系映射呢?接下来我们来一一举例出
Hibernate在实现ORM功能的时候主要用到的文件有:映射类(*.java)、映射文件(*.hbm.xml)和数据库配置文件(*hibernate.cfg.xml)
编写 Emp类
编写Dept类
1.多对一关联映射(many-to-one):
接下来,我们来编写实体类的映射文件
/* *查询员工所在的部门,多对一关系 * */ @Test public void test01(){ /*调用HibernateUtil工具类的getSession()方法获取session*/ Session session = HibernateUtil.getSession(); /*延迟加载出员工对象*/ Emp emp = session.load(Emp.class, 1); /*输出员工所在的部门名称*/ System.out.println(emp.getDept().getDeptname()); } /* * 多对一单项关联 * */ @Test public void testmanytoone(){ /*调用HibernateUtil工具类的getSession()方法获取session*/ Session session = HibernateUtil.getSession(); /*创建Transaction事务*/ Transaction tr=session.beginTransaction(); /*创建部门对象*/ Dept dept=new Dept(); dept.setDeptname("发财二部"); /*创建员工对象*/ Emp emp=new Emp(); emp.setEmpname("许先生"); /*将dept对象放入员工Emp对象中*/ emp.setDept(dept); session.save(dept); session.save(emp); /*提交事务*/ tr.commit(); } @Test /* * 按照指定的部门编号查询对应的员工信息 * */ public void test3(){ /*调用HibernateUtil工具类的getSession()方法获取session*/ Session session = HibernateUtil.getSession(); /*创建Transaction事务*/ Transaction tx=session.beginTransaction(); /*编写hql语句,按照指定的部门编号查询对应的员工信息*/ String hql="from Emp e where e.dept.deptno=1"; /*将生成的Bean为query对象装入list*/ Query query = session.createQuery(hql); List<Emp> list = query.list(); /*输出对应的部门的员工名称*/ for (Emp item : list) { System.out.println(item.getEmpname()); } tx.commit(); } /*查询所有的员工和各自对应的部门*/ @Test public void test4(){ /*调用HibernateUtil工具类的getSession()方法获取session*/ Session session = HibernateUtil.getSession(); /*创建Transaction事务*/ Transaction tr =session.beginTransaction(); /*编写hql,查询所以员工*/ String hql="from Emp"; /*将生成的Bean为query对象装入list*/ Query query = session.createQuery(hql); List<Emp> list = query.list(); /*输出所以员工和每个员工对应的部门*/ for (Emp emp:list) { System.out.println(emp.getDept().getDeptname()); System.out.println(emp.getEmpname()+"----------------"+emp.getEmpno()); } } /*修改员工的部门编号*/ @Test public void test5(){ Session session = HibernateUtil.getSession(); Transaction tr =session.beginTransaction(); Emp emp = session.load(Emp.class, 1); Dept dept = session.load(Dept.class, 2); emp.setDept(dept); tr.commit(); }
2. 一对多关联映射(one-to-many):
这个时候我们需要在Dept实体加入Set集合
那么为什么要用set集合而不用list呢
首先,你要清楚List和Set的区别:List是有序和可重复;Set是无序,但是不能重复.
其次,在一对多关联中.想象一下这种情况:你要更新从表记录;
从List中得到从表的一个对象引用,然后你对这样对象修改后,又放回List,你的List中就包括两个从表对象的引用.你在保存时,这两个引用,你觉得会保存两次还是一次?
而如果是Set,你得到从表对象的引用,之后修改从表对象的内容,你再往Set里面放,Set里面因为已经有这个从表对象的引用,就不会再给里面加.这样,你的Set里面还是只有一个从表对象的引用.这样你保存,这个从表对象只保存一次.
映射文件 Dept.hbm.xml
1 <?xml version="1.0"?> 2 <!DOCTYPE hibernate-mapping PUBLIC 3 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 5 <hibernate-mapping package="cn.hibernate.day04.entity"> 6 <!--实体 name=实体端的内容 column=DB端的内容--> 7 <class name="Dept" table="DEPT"> 8 <!--和底层数据表对应的主键 业务意义--> 9 <id name="deptno" column="DEPTNO"> 10 <generator class="native"></generator> 11 </id> 12 <property name="deptname" column="DEPTNAME" length="32"></property> 13 <!--一对多--> 14 <set name="emps" cascade="save-update,persist" table="Emp" > 15 <key column="deptno"></key> 16 <one-to-many class="Emp"></one-to-many> 17 </set> 18 </class> 19 </hibernate-mapping>
接下来是列子
/*查询所有的部门,并把部门所对应的员工信息检索出来,一对多关系*/ @Test public void testonetomany(){ /*编写hql语句:查询所有部门*/ String hql="from Dept"; /*调用HibernateUtil工具类的getSession()方法获取session*/ Session session = HibernateUtil.getSession(); /*将生成的Bean为query对象装入list*/ Query query = session.createQuery(hql); List<Dept> list = query.list(); /*遍历部门输出部门名称*/ for (Dept dept:list) { System.out.println(dept.getDeptname()+"--------------"); /*根据部门实体中的Set集合获取员工信息,遍历输出*/ for (Emp emp:dept.getEmps()) { System.out.println(emp.getEmpname()+"--------------"); } } } /*添加部门和员工信息,一对多关系*/ @Test public void testsaveDept(){ /*调用HibernateUtil工具类的getSession()方法获取session*/ Session session = HibernateUtil.getSession(); /*创建Transaction事务*/ Transaction tx=session.beginTransaction(); /*创建部门对象*/ Dept dept=new Dept(); dept.setDeptname("财务部"); /*创建员工对象*/ Emp emp=new Emp(); emp.setEmpname("笑醒"); /*调用add()方法将emp对象放入dept,如果不写,添加的时候不会添加员工信息*/ dept.getEmps().add(emp); session.save(dept); /*提交事务*/ tx.commit(); }
注意:它与多对一的区别是维护的关系不同
*多对一维护的关系是:多指向一的关系,有了此关系,加载多的时候可以将一加载上来
*一对多维护的关系是:一指向多的关系,有了此关系,在加载一的时候可以将多加载上来
3.多对多单向关联(many-to-many)
首先我们需要两个拥有多对多关系的类,生活中多对多关系的列子很多,随便就能列出了,比如学生和老师,程序员和项目,那么我们用程序员员工和项目来做列子
//员工实体 public class Employee { private Integer empid; private String empname; private Set<Project> projects = new HashSet<Project>();
}
/** * Created by Happy on 2017-09-26. * 工程实体 */ public class Project { private Integer proid; private String proname; private Set<Employee> employees=new HashSet<Employee>();
接下来我们来写两个配置文件
Project.hbm.xml
<?xml version="1.0"?> <!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.hibernate.day05.entity"> <!--实体 name=实体端的内容 column=DB端的内容--> <class name="Project" table="PROJECT"> <!--和底层数据表对应的主键 业务意义--> <id name="proid" column="PROID"> <generator class="native"></generator> </id> <property name="proname" column="PRONAME" length="32"></property> </class> </hibernate-mapping>
Employee.hbm.xml
<?xml version="1.0"?> <!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.hibernate.day05.entity"> <!--实体 name=实体端的内容 column=DB端的内容--> <class name="Employee" table="EMPLOYEE"> <!--和底层数据表对应的主键 业务意义--> <id name="empid" column="EMPID"> <generator class="native"></generator> </id> <property name="empname" column="EMPNAME" length="32"></property> <!-- Table属性:中间表(集合表) key子元素:集合外键(引用当前表主键的外键),里面的Column指的是在中间表中的列名 many-to-many子元素:里面的class属性是指关联的类型,column是指引用Project的主键值 --> <set name="projects" cascade="save-update" table="EMPPRO" > <key column="EPMRID"></key> <many-to-many class="Project" column="RPROID"></many-to-many> </set> </class> </hibernate-mapping>
接下来是测试列子
/*添加多对多单向关联信息*/ @Test public void test01(){ /*调用HibernateUtil工具类的getSession()方法获取session*/ Session session=HibernateUtil.getSession(); /*创建Transaction事务*/ Transaction tx=session.beginTransaction(); /*创建员工对象*/ Employee emp1=new Employee(); emp1.setEmpname("没事了大疯狂拉升"); /*创建项目对象*/ Project pro1=new Project(); pro1.setProname("海淀花园"); Project pro2=new Project(); pro2.setProname("海上花园"); emp1.getProjects().add(pro1); emp1.getProjects().add(pro2); session.save(emp1); session.save(pro1); session.save(pro2); tx.commit(); } /*查询项目Set集合中对象的个数*/ @Test public void test02(){ Session session = HibernateUtil.getSession(); Transaction transaction = session.beginTransaction(); Employee employee = session.load(Employee.class, 1); Set<Project> projects=employee.getProjects(); System.out.println(projects.size()); }
4.多对多双向关联(many-tomany)
需要在Project.hbm.xml加入set
<?xml version="1.0"?> <!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.hibernate.day05.entity"> <!--实体 name=实体端的内容 column=DB端的内容--> <class name="Project" table="PROJECT"> <!--和底层数据表对应的主键 业务意义--> <id name="proid" column="PROID"> <generator class="native"></generator> </id> <property name="proname" column="PRONAME" length="32"></property> <set name="employees" table="EMPPRO" > <key column="RPROID" ></key> <many-to-many column="EPMRID" class="Employee" ></many-to-many> </set> </class> </hibernate-mapping>
测试类
/*添加多对多单向关联信息*/ @Test public void test01(){ /*调用HibernateUtil工具类的getSession()方法获取session*/ Session session=HibernateUtil.getSession(); /*创建Transaction事务*/ Transaction tx=session.beginTransaction(); /*创建员工对象*/ Employee emp1=new Employee(); emp1.setEmpname("没事了大疯狂拉升"); /*创建项目对象*/ Project pro1=new Project(); pro1.setProname("海淀花园"); Project pro2=new Project(); pro2.setProname("海上花园"); emp1.getProjects().add(pro1); emp1.getProjects().add(pro2); session.save(emp1); /* session.save(pro1); session.save(pro2);*/ tx.commit(); }
关联关系中常用属性
1.级联(cascade)
我们以部门和员工的关系为例讲解一对多关联关系映射时,删除部门时,如果部门有关联的员工且inverse属性为false,那么由于可以维护关联关系,它就会先把关联的员工的外键列设为null值,再删除自己。但是此刻希望删除部门时,就附带着把该部门下的所有员工都删掉,这时就需要引入cascade属性了。
当Hibernate持久化一个临时对象时,在默认情况下,它不会自动持久化所关联的其他临时对象,而是会抛出TransientObjectException。如果设定many-to-one元素的cascade属性为save-update的话,可实现自动持久化所关联的对象。如:
2. set元素的inverse属性
inverse有两属性:
1 .false 设置为false,则为主动方,由主动方负责维护关联关系,默认是false
2 .true 设置为true,则不为主动方,并且不负责维护关联关系,而是由不包含这个关系的一方来维护这个关系
3.order_by 其作用就是对集合中的数据进行排序