http://blog.csdn.net/yerenyuan_pku/article/details/70556208

Hibernate中的多表操作

在实际开发中,我们不可能只是简简单单地去操作单表,绝大部分都是要对多表进行操作的。所以本文就来讲述Hibernate中的多表操作,讲之前,先复习一下使用SQL语句是如何进行多表操作的。提示:本文所有案例代码的编写都是建立在前文Hibernate检索方式概述的案例基础之上的!!!

SQL多表操作

SQL多表操作可分为如下几类:

  • 交叉连接(CROSS JOIN) 
    交叉连接其实是没有实际意义的,它会产生迪卡尔积。例如:

    SELECT * FROM t_customer CROSS JOIN t_order;
  • 内连接(INNER JOIN ON) 
    使用内连接,它只能将有关联的数据得到。例如:

    SELECT * FROM t_customer AS c INNER JOIN t_order AS o ON c.id=o.c_customer_id; 
  • 内连接还有一种隐式内连接,它使用”逗号”将表分开,使用WHERE来消除迪卡尔积。例如:

    SELECT * FROM t_customer AS c, t_order o WHERE c.id=o.c_customer_id;
  • 外连接 
    外连接又分为:

    • 左外连接(LEFT OUTER JOIN):它是以左表为基准关联数据,说的大白话一点就是它展示的数据只是在左表中有的,右表中没有的不管。例如:

      SELECT * FROM t_customer c LEFT OUTER JOIN t_order o ON c.id=o.c_customer_id;
    • 右外连接(RIGHT OUTER JOIN):它是以右表为基准关联数据,说的大白话一点就是它展示的数据只是在右表中有的,左表中没有的不管。例如:

      SELECT * FROM t_customer c RIGHT OUTER JOIN t_order o ON c.id=o.c_customer_id;

    提示:OUTER可以省略。

HQL多表操作

HQL多表操作可分为下面几类:

  1. 交叉连接
  2. 内连接 
    • 显示内连接
    • 隐式内连接
    • 迫切内连接
  3. 外连接 
    • 左外连接
    • 迫切左外连接
    • 右外连接

注意:在Hibernate框架中有迫切连接的这一概念,而在SQL中是没有的

内连接

显示内连接

显示内连接使用的是inner join with。如果是在MySQL中使用显示内连接,那么我们就要这样书写SQL语句:

select * from t_customer(表名)inner join t_order(表名) on 条件

但在Hibernate框架中,我们则要书写这样的hql语句:

from Order o inner join o.c

为了便于测试,在cn.itheima.test包下编写一个HQLJoinTest单元测试类,并在该类中编写这样的一个测试方法:

public class HQLJoinTest {// 测试显示内连接@Testpublic void test1() { Session session = HibernateUtils.openSession(); session.beginTransaction(); String hql = "from Order o inner join o.c"; Query query = session.createQuery(hql); List<Object[]> list = query.list(); // 结果是一个List<Object[]>集合,而Object[]中装入的是Customer和Order对象。 for (Object[] objs : list) { for (Object obj : objs) { System.out.print(obj + "\t"); } System.out.println(); } session.getTransaction().commit(); session.close(); } }

运行以上test1方法,Eclipse控制台打印如下: 

可得出结论:query.list()返回的结果是一个List集合,集合存放的是Object[],而Object[]中装入的无非是Customer和Order对象。 
在Hibernate框架中,我们也可书写这样的hql语句:

from Customer c inner join c.orders
  • 1
  • 1

为了进行测试,将HQLJoinTest单元测试类中的test1方法改为:

public class HQLJoinTest {// 测试显示内连接@Testpublic void test1() { Session session = HibernateUtils.openSession(); session.beginTransaction(); String hql = "from Customer c inner join c.orders"; Query query = session.createQuery(hql); List<Object[]> list = query.list(); // 结果是一个List<Object[]>集合,而Object[]中装入的是Customer和Order对象。 for (Object[] objs : list) { for (Object obj : objs) { System.out.print(obj + "\t"); } System.out.println(); } session.getTransaction().commit(); session.close(); } }

运行以上test1方法,Eclipse控制台打印如下: 

当然了,我们又可书写这样的hql语句:

from Customer c inner join c.orders with c.id=1
  • 1
  • 1

即使用with再添加一个条件。所以为了便于进行测试,将HQLJoinTest单元测试类中的test1方法改为:

public class HQLJoinTest {// 测试显示内连接@Testpublic void test1() { Session session = HibernateUtils.openSession(); session.beginTransaction(); String hql = "from Customer c inner join c.orders with c.id=1"; Query query = session.createQuery(hql); List<Object[]> list = query.list(); // 结果是一个List<Object[]>集合,而Object[]中装入的是Customer和Order对象。 for (Object[] objs : list) { for (Object obj : objs) { System.out.print(obj + "\t"); } System.out.println(); } session.getTransaction().commit(); session.close(); } }

运行以上test1方法,Eclipse控制台打印如下: 

隐式内连接

隐式内连接也与我们在SQL中的操作不一样,它是通过.运算符来关联的。值得一提的是,隐式内连接使用频率并不高,大家知道就OK了。如果是在MySQL中使用隐式内连接,那么我们就要这样书写SQL语句:

select * from t_customer,t_order where 条件
  • 1
  • 1

但在Hibernate框架中,我们则要书写这样的hql语句:

from Order o where o.c.id=1

为了便于进行测试,在HQLJoinTest单元测试类中编写如下方法:

public class HQLJoinTest {// 测试隐式内连接(使用频率不高。大家知道就OK了)@Testpublic void test2() { Session session = HibernateUtils.openSession(); session.beginTransaction(); String hql = "from Order o where o.c.id=1"; Query query = session.createQuery(hql); List list = query.list(); System.out.println(list); session.getTransaction().commit(); session.close(); } }

运行以上test2方法,Eclipse控制台打印如下: 

迫切内连接

迫切内连接使用的是inner join fetch。迫切内连接得到的结果是直接封装到PO类中,而内连接得到的是Object[]数组,数组中封装的是PO类对象。下面我们来验证这一点,在HQLJoinTest单元测试类中编写如下方法:

public class HQLJoinTest {// 迫切内连接@Testpublic void test3() { Session session = HibernateUtils.openSession(); session.beginTransaction(); String hql = "from Order o inner join fetch o.c"; Query query = session.createQuery(hql); List list = query.list(); // 结果是一个List<>集合,集合中装入的是from后面的对象。 System.out.println(list); session.getTransaction().commit(); session.close(); } }

运行以上test3方法,Eclipse控制台打印如下: 

可得出结论:query.list()返回的结果是一个List集合,集合中装入的是from后面的对象。如还有疑问,可将以上test3方法改为:

public class HQLJoinTest {// 迫切内连接@Testpublic void test3() { Session session = HibernateUtils.openSession(); session.beginTransaction(); String hql = "from Customer c inner join fetch c.orders"; Query query = session.createQuery(hql); List list = query.list(); // 结果是一个List<>集合,集合中装入的是from后面的对象。 System.out.println(list); session.getTransaction().commit(); session.close(); } }

运行以上test3方法,Eclipse控制台打印如下: 

从这里我们也能看出,迫切内连接底层也是执行的inner join,只不过数据结果封装到了对象中了。但问题又来了,我们查询的是两张表的信息,那就会得到合并后的结果,如果是查Order则没问题,但是你要查Customer,Customer就会出现很多重复的数据,这个时候,我们就需要使用关键字——distinct去消除重复了。故应将test3方法改为:

public class HQLJoinTest {// 迫切内连接@Testpublic void test3() { Session session = HibernateUtils.openSession(); session.beginTransaction(); String hql = "select distinct c from Customer c inner join fetch c.orders"; Query query = session.createQuery(hql); List<Customer> list = query.list(); for (Customer order : list) { System.out.println(order); } session.getTransaction().commit(); session.close(); } }

再次运行以上test3方法,Eclipse控制台打印如下: 
 
结论:使用迫切连接,结果可能出现重复,所以要使用distinct来去除重复。

外连接

左外连接

左外连接使用的是left outer join。以码明示,在HQLJoinTest单元测试类中编写如下方法:

public class HQLJoinTest {// 演示外连接@Testpublic void test4() { Session session = HibernateUtils.openSession(); session.beginTransaction(); List<Object[]> list = session.createQuery("from Customer c left outer join c.orders").list(); // 左外连接 for (Object[] objs : list) { for (Object obj : objs) { System.out.print(obj + "\t"); } System.out.println(); } session.getTransaction().commit(); session.close(); } }

运行以上test4方法,Eclipse控制台打印如下: 

右外连接

右外连接使用的是right outer join。以码明示,将HQLJoinTest单元测试类中的test4方法改为:

public class HQLJoinTest {// 演示外连接@Testpublic void test4() { Session session = HibernateUtils.openSession(); session.beginTransaction(); List<Object[]> list = session.createQuery("from Customer c right outer join c.orders").list(); // 右外连接 for (Object[] objs : list) { for (Object obj : objs) { System.out.print(obj + "\t"); } System.out.println(); } session.getTransaction().commit(); session.close(); } }

运行以上test4方法,Eclipse控制台打印如下: 

迫切左外连接

迫切左外连接使用的是left outer join fetch。以码明示,在HQLJoinTest单元测试类中编写如下方法:

public class HQLJoinTest {// 演示迫切左外连接@Testpublic void test5() { Session session = HibernateUtils.openSession(); session.beginTransaction(); // 注意:fetch不可以与单独条件的with一起使用 List<Customer> list = session.createQuery("select distinct c from Customer c left outer join fetch c.orders with c.id=1").list(); for (Customer customer : list) { System.out.println(customer); } session.getTransaction().commit(); session.close(); } }

运行以上test5方法,会发现报如下异常: 

异常发生原因:fetch不可以与单独条件的with一起使用。如果非要让fetch与单独的一个条件使用,则必须使用where关键字。故将HQLJoinTest单元测试类中的test5方法改为:

public class HQLJoinTest {// 演示迫切左外连接@Testpublic void test5() { Session session = HibernateUtils.openSession(); session.beginTransaction(); // 注意:fetch不可以与单独条件的with一起使用 List<Customer> list = session.createQuery("select distinct c from Customer c left outer join fetch c.orders where c.id=1").list(); for (Customer customer : list) { System.out.println(customer); } session.getTransaction().commit(); session.close(); } }

再次运行以上test5方法,Eclipse控制台打印如下: 

Hibernate中的Session管理

Hibernate提供了三种管理Session的方式:

  1. Session对象的生命周期与本地线程绑定(ThreadLocal)
  2. Session对象的生命周期与JTA事务绑定(也即分布式事务管理,应用在分布式数据库里面,在此并不打算讲解)
  3. Hibernate委托程序来管理Session的生命周期

我们之前一直所使用的是第三种方式,即通过程序获取一个Session对象,然后使用它,最后关闭它(即session.close();)。 
在实际开发中我们一般使用的是前两种,但由于第二种方式是基于分布式数据库而言的,所以在此主要介绍关于本地线程绑定Session这种方式,这种方式的使用步骤为:

  1. 需要在hibernate.cfg.xml核心配置文件添加如下配置:

    <property name="hibernate.current_session_context_class">thread</property>
  2. 在获取Session时不要再使用openSession()方法而是使用getCurrentSession()方法。故应在HibernateUtils工具类中添加如下方法:

    public static Session getCurrentSession() {return sessionFactory.getCurrentSession();
    }

    如此一来,HibernateUtils工具类的代码就变为:

    public class HibernateUtils {private static Configuration config;private static SessionFactory sessionFactory; static { config = new Configuration().configure(); sessionFactory = config.buildSessionFactory(); } public static Session openSession() { return sessionFactory.openSession(); } public static Session getCurrentSession() { return sessionFactory.getCurrentSession(); } }

本地线程绑定Session这种方式的大概内部原理可用下图来表示: 

接下来,我们就要在cn.itheima.test包下编写一个SessionManageTest单元测试类测试Session绑定到线程中,即在SessionManageTest单元测试类中编写如下方法:

public class SessionManageTest {// 测试Session绑定到线程中@Testpublic void test1() { // 这时每一次获取都是一个新的Session Session s1 = HibernateUtils.openSession(); Session s2 = HibernateUtils.openSession(); System.out.println(s1 == s2); // false Session s3 = HibernateUtils.getCurrentSession(); Session s4 = HibernateUtils.getCurrentSession(); System.out.println(s3 == s4); // true } }

运行以上方法,Eclipse控制台打印:

false 
true

关于getCurrentSession方法使用时的注意事项

例如,我们要简单查询id为1的客户,我们相当然地会在SessionManageTest单元测试类中编写如下方法:

public class SessionManageTest {@Testpublic void test2() { Session session = HibernateUtils.getCurrentSession(); session.beginTransaction(); Customer customer = session.get(Customer.class, 1); System.out.println(customer); session.getTransaction().commit(); session.close(); } }

上述代码执行后,会产生如下问题: 

产生该问题的原因:使用getCurrentSession方法获取的与线程绑定的session对象,在事务关闭(提交)时,session对象也会close掉,简单说,就不需要我们再手动close掉session对象了。故应将test2方法改为:

public class SessionManageTest {@Testpublic void test2() { Session session = HibernateUtils.getCurrentSession(); session.beginTransaction(); Customer customer = session.get(Customer.class, 1); System.out.println(customer); session.getTransaction().commit(); } }

转载于:https://www.cnblogs.com/telwanggs/p/6964040.html

(转)Hibernate中的多表操作相关推荐

  1. Hibernate 中出现 xxx表 is not mapped xxx的问题

    导航 Hibernate 中出现 xxx表 is not mapped xxx的问题 案例 Hibernate 中出现 xxx表 is not mapped xxx的问题 遇到这样的问题基本就是小白了 ...

  2. hibernate中一对多表关系操作(7)

    1.基本操作,保存客户.联系人,并设置它们的关联 public void test01(){Session session = HibernateUtils.OpenSession();Transac ...

  3. Spring整合Hibernate中自动建表

    Java代码   <bean id="sessionFactory" class="org.springframework.orm.hibernate3.Local ...

  4. mysql中的回表操作

    什么是回表查询? 一般情况下是:先到普通索引上定位主键值,再到聚集索引上定位行记录,它的性能较扫一遍索引树低. 具体解释: 我们自己建的索引不管是单列索引还是联合索引,都称为普通索引,主键索引是聚簇索 ...

  5. 《Java从入门到放弃》框架入门篇:hibernate中的多表对应关系(二)

    前一篇讲完了一对多的关系,通过与JDBC对比应该能发现,是不是比JDBC简单了很多? 我们只需要把对象只间的包含或对应关系理清楚,完全不用我们自己来写SQL语句.所以使用hibernate框架后,我们 ...

  6. django学习笔记--数据库中的多表操作

    1.Django数据库----多表的新增操作 1.一对一模式下新增 创建一个详情对象,把这个对象赋值给创建的新的user对象 author_detail = models.AuthorDetail.o ...

  7. java hibernate 自定义排序_java – 如何在hibernate中对关联表进行排序?

    根据JPA规范: The property or field name must correspond to that of a persistent property or field of the ...

  8. python代码函数字符查询宝典书籍_Django基础五之django模型层(一)单表操作

    二 单表操作 一.创建表 创建模型 创建名为book的app,在book下的models.py中创建模型: from django.db importmodels#Create your models ...

  9. Django框架——模型层单表操作、模型层多表操作、模型层常用和非常用字段和参数、模型层进阶

    文章目录 1 模型层-单表操作 一 ORM简介 二 单表操作 2.1 创建表 1 创建模型 2 更多字段 3 更多参数 4 settings配置 5 增加,删除字段 2.2 添加表纪录 2.3 查询表 ...

最新文章

  1. 保护物联网的数据隐私和在线安全的7种方式
  2. A Bug's Life(向量偏移)
  3. Ubuntu安装新英伟达驱动出现问题解决方法
  4. 为什么ppt图形卡配置不正确_电脑配置 | 赛博朋克2077什么配置能玩
  5. python适合做后端开发吗-Python后端开发是什么职位?
  6. docker多主机网络方案
  7. Zookeeper 服务注册与发现01——服务提供者
  8. ifm management of technology q and a session 2
  9. HTTPS原理全面介绍【备查】
  10. ASP.NET MVC 多语言开发简单案例
  11. Q96:PT(3.3):大理石纹理(Marble Texture)
  12. 集成计划排程计划以及管控体系的几个特征
  13. PHP获取表单数据的方法有几种,php获取表单数据的两种方法说明
  14. x230 linux驱动程序,佳能 ThinkPad X230 Tablet 驱动程序下载-更新佳能软件(平板电脑)...
  15. 网吧网吧无盘服务器配置,网吧无盘服务器配置杂谈
  16. python编写计算方差的函数_基于python计算滚动方差(标准差)talib和pd.rolling函数差异详解...
  17. 《Vue插件》瀑布流插件vue-masonry的使用与踩坑记录
  18. python日常实用小脚本-Python实现自动挂机脚本 | 沐雨浥尘
  19. APP逆向之易班(第一篇)
  20. Nginx获取真实用户IP

热门文章

  1. linux之EXT2文件系统--理解block/block group/索引结点inode/索引位图
  2. Apache 目录结构与配置指令
  3. (46)VHDL实现4位桶性形移位器
  4. (79)Verilog HDL系统函数和任务:$write
  5. (16)FPGA面试技能提升篇(Python)
  6. 基于FPGA实现SDI转Camera Link接口
  7. git 创建webpack项目_使用webpack手动创建一个完整项目的全过程
  8. php无限次执行函数,php-PHP一个方法根据传递值怎么执行多次?
  9. Linux根文件组织架构
  10. varnish工作原理详细讲解