(转)Hibernate中的多表操作
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多表操作可分为下面几类:
- 交叉连接
- 内连接
- 显示内连接
- 隐式内连接
- 迫切内连接
- 外连接
- 左外连接
- 迫切左外连接
- 右外连接
注意:在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的方式:
- Session对象的生命周期与本地线程绑定(ThreadLocal)
- Session对象的生命周期与JTA事务绑定(也即分布式事务管理,应用在分布式数据库里面,在此并不打算讲解)
- Hibernate委托程序来管理Session的生命周期
我们之前一直所使用的是第三种方式,即通过程序获取一个Session对象,然后使用它,最后关闭它(即session.close();
)。
在实际开发中我们一般使用的是前两种,但由于第二种方式是基于分布式数据库而言的,所以在此主要介绍关于本地线程绑定Session这种方式,这种方式的使用步骤为:
需要在hibernate.cfg.xml核心配置文件添加如下配置:
<property name="hibernate.current_session_context_class">thread</property>
在获取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中的多表操作相关推荐
- Hibernate 中出现 xxx表 is not mapped xxx的问题
导航 Hibernate 中出现 xxx表 is not mapped xxx的问题 案例 Hibernate 中出现 xxx表 is not mapped xxx的问题 遇到这样的问题基本就是小白了 ...
- hibernate中一对多表关系操作(7)
1.基本操作,保存客户.联系人,并设置它们的关联 public void test01(){Session session = HibernateUtils.OpenSession();Transac ...
- Spring整合Hibernate中自动建表
Java代码 <bean id="sessionFactory" class="org.springframework.orm.hibernate3.Local ...
- mysql中的回表操作
什么是回表查询? 一般情况下是:先到普通索引上定位主键值,再到聚集索引上定位行记录,它的性能较扫一遍索引树低. 具体解释: 我们自己建的索引不管是单列索引还是联合索引,都称为普通索引,主键索引是聚簇索 ...
- 《Java从入门到放弃》框架入门篇:hibernate中的多表对应关系(二)
前一篇讲完了一对多的关系,通过与JDBC对比应该能发现,是不是比JDBC简单了很多? 我们只需要把对象只间的包含或对应关系理清楚,完全不用我们自己来写SQL语句.所以使用hibernate框架后,我们 ...
- django学习笔记--数据库中的多表操作
1.Django数据库----多表的新增操作 1.一对一模式下新增 创建一个详情对象,把这个对象赋值给创建的新的user对象 author_detail = models.AuthorDetail.o ...
- java hibernate 自定义排序_java – 如何在hibernate中对关联表进行排序?
根据JPA规范: The property or field name must correspond to that of a persistent property or field of the ...
- python代码函数字符查询宝典书籍_Django基础五之django模型层(一)单表操作
二 单表操作 一.创建表 创建模型 创建名为book的app,在book下的models.py中创建模型: from django.db importmodels#Create your models ...
- Django框架——模型层单表操作、模型层多表操作、模型层常用和非常用字段和参数、模型层进阶
文章目录 1 模型层-单表操作 一 ORM简介 二 单表操作 2.1 创建表 1 创建模型 2 更多字段 3 更多参数 4 settings配置 5 增加,删除字段 2.2 添加表纪录 2.3 查询表 ...
最新文章
- 保护物联网的数据隐私和在线安全的7种方式
- A Bug's Life(向量偏移)
- Ubuntu安装新英伟达驱动出现问题解决方法
- 为什么ppt图形卡配置不正确_电脑配置 | 赛博朋克2077什么配置能玩
- python适合做后端开发吗-Python后端开发是什么职位?
- docker多主机网络方案
- Zookeeper 服务注册与发现01——服务提供者
- ifm management of technology q and a session 2
- HTTPS原理全面介绍【备查】
- ASP.NET MVC 多语言开发简单案例
- Q96:PT(3.3):大理石纹理(Marble Texture)
- 集成计划排程计划以及管控体系的几个特征
- PHP获取表单数据的方法有几种,php获取表单数据的两种方法说明
- x230 linux驱动程序,佳能 ThinkPad X230 Tablet 驱动程序下载-更新佳能软件(平板电脑)...
- 网吧网吧无盘服务器配置,网吧无盘服务器配置杂谈
- python编写计算方差的函数_基于python计算滚动方差(标准差)talib和pd.rolling函数差异详解...
- 《Vue插件》瀑布流插件vue-masonry的使用与踩坑记录
- python日常实用小脚本-Python实现自动挂机脚本 | 沐雨浥尘
- APP逆向之易班(第一篇)
- Nginx获取真实用户IP
热门文章
- linux之EXT2文件系统--理解block/block group/索引结点inode/索引位图
- Apache 目录结构与配置指令
- (46)VHDL实现4位桶性形移位器
- (79)Verilog HDL系统函数和任务:$write
- (16)FPGA面试技能提升篇(Python)
- 基于FPGA实现SDI转Camera Link接口
- git 创建webpack项目_使用webpack手动创建一个完整项目的全过程
- php无限次执行函数,php-PHP一个方法根据传递值怎么执行多次?
- Linux根文件组织架构
- varnish工作原理详细讲解