• 1. HQL查询petrelsky5@tom.com
  • 2. 学习目标HQL 查询 Query 接口及其主要方法 Select 子句 更新与删除 引用查询 联合查询 子查询 数据加载方式 Sql 查询 分页查询 管理 Session ThreadLocal 接口的使用
  • 3. HQL 查询HQL(Hibernate Query Language):具有与sql语言类似的语法规范,只不过sql是针对于数据表字段进行查询,而 HQL 是针对持久化对象,它用来取得对象. HQL 是完全面向对象的,具备继承,多态和关联等特性. 除了JAVA类和属性 外HQL对大小写不敏感 HQL 查询依赖于 Query 类,每个 Query 实例对应一个查询对象。
  • 4. Query 接口Query 接口用来执行 HQL,Query 接口实例可以从 Session 对象 session 中生成: Query query = session.createQuery(“from User u where u.userName like ?”); Query 的主要方法: setXXX()方法:用于设置HQL中的问号或变量的值 list()方法:返回查询结果,并把查询结果转变为 List对象 excuteUpdate()方法:执行更新或删除语句
  • 5. setXXX()方法setXXX()方法:用于设置HQL中的 ? 或变量的值,每 一个方法都有两种重载形式,以 setString()为例: setString(int position,String value):用于设置HQL中 的 ”?” 的值;期中position代表 ”?” 在HQL中的位 置,value为 ”?” 设置的值.例如: Query query = session.createQuery (“from User u where u.age > ? and u.userName like ?”); query.setInteger(0,12); query.setString(1,”%Tom%”);
  • 6. setXXX()方法setXXX()方法: setString(int position,String value): setString(String paraName,String value):用于设置HQL 中”:”后跟变量的值;其中paramName代表HQL中”:”后跟变 量,value为该变量设置的值: Query query = session.createQuery (“from User user where u.age > :minAge and u.userName like :userName”); query.setInteger(“minAge”,22); query.setString(“userName”,”%Tom%”); where 子句中,可以通过比较操作符指定甄选条件:=, <>, <, >, >=, <=, between, not between, in, not in, is, like. 可以通过 and, or等逻辑运算符组合各个逻辑表达式。
  • 7. list()方法返回查询结果,并把查询结果转变为 List 接口的实例: Query query = session.createQuery(“from User u where u.age > ?”); query.setInteger(0,22); List list = query.list(); while(int I = 0; i < list.size(); i++){ user = (User)list.get(i); System.out.println(user.getUserName()); }
  • 8. executeUpdate()方法该方法用于执行更新或删除语句。常用于批量删除 或批量更新操作。例如: String hql = "update Book set name = :name where id = :id"; Query query = session.createQuery(hql); query.setString("name","hahahaha"); query.setInteger("id",205); query.executeUpdate();
  • 9. select 子句select子句:如果要查询两个以上的属性,需要使用 select 子句。查询结果会以数组的方式返回,数组 中依次包含了所获取的属性数据: Query query = session.createQuery(“select s.name,s.sex from Student s ”); List list = query.list(); for(int i = 0; i < list.size(); i++){ Object [] obj = (Object[])list.get(i); System.out.println(obj[0] + “ 的性别是:” + obj[1]); } 若只查询了一个属性。则返回的 List 数据结构中,每个条目都是一个相应类型的数据
  • 10. select 子句select子句:如果要查询两个以上的属性,查询结果 会以数组的方式返回,还可以将一个 object[] 中 所有成员封装成一个对象: Query query = session.createQuery(“select new Student(s.name,s.sex) from Student s”); List list = query.list(); for(int i = 0; i < list.size(); i++){ Student stu = (Student)list.get(i); System.out.println(stu.getName + “ 的性别是 ” + stu.getSex()); } 注:要正确运行,需要在Student类中加入一个相应的构造函数。这种方式的查询结果中 Student 对象除了在构造时赋予的属性值之外,其他属性均为未赋值状态。这意味着无法通过 session 对此对象进行更新
  • 11. select 子句可以在 select 子句中子句中使用统计函数: count(),min(),max(),sum(),avg()等 select count(*) from Student 用distinct去除重复数据 select distinct s.age from Student as s 使用原生 sql 函数 select upper(user.name) from User as user
  • 12. 更新与删除通过 delete 和 update 子句可以进行数据的删除与更新:
  • 13. 分组与排序HQL 通过 order by 子句实现对查询结果的排序: from User user order by user.name, user.age desc 通过 group by 子句可以进行分组统计,通过 having 子句可以对 group by 返回的结果集进行甄选:
  • 14. 引用查询Hibernate 提供了 HQL 可配置化的内置支持。 在 .hbm.xml 中通过 query 节点定义查询语句(与 class 同级) 通过 Session.getNamedQuery 方法从配置文件中调用相应 的 HQL
  • 15. 联合查询SQL 中通过 join 子句实现多表之间的联合查询。 HQL 提供了以下几种联合查询机制 inner join left outer join right outer join full join(not usually userful)orders_tablecustomerss_table
  • 16. left joinLeft join 返回 ”first_table” 中所有的行尽管在 ” second_table”中没有相匹配的数据 Hibernate 对应语句: from Customers as customer left join customer.orders as orderSQL 中的 on c.id = o.customerid 子句所描述的对应关系在 Hibernate 中已经由映射文件指定,因此 HQL 并没有对应的子句; 得到的结果集中,每个条目都是一个 Object 数组,其中包含了一个 Customers 对象与其对应的 Orders 对象
  • 17. left join 例程
  • 18. right joinright join返回 ”second_table” 中所有的行尽管在 ”first_table” 中没有相匹配的数据。 Hibernate 对应语句: from Customers as customer right join customer.orders as order
  • 19. inner joininner join返回的结果集是两个表中所有相匹配的数据。 Hibernate 对应语句: from Customers as customer inner join customer.orders as order
  • 20. fetch如果希望查询得到的是 Customers 对象。则应该在查询语句中加上 fetch 关键字。 from Customers as customer inner join fetch customer.orders as order 在查询 Customers 对象的时候,默认只有 Customers 的内容,并不包含 orders 集合的信息,在 Customers.hbm.xml 里设置lazy=“false”可以同时取出关联的所有 orders 内容.但若既想要 hibernate 默认的性能又想要临时的灵活性,则可以使用 fetch。总之,fetch就是在代码这一层给你一个主动抓取得机会 fetch 关键字只对 inner join 和 left join 有效。对于 right join 而言, 由于作为关联对象的 Customers 对象可能为 null,所以无法通过 fetch 关键字强制 Hibernate 进行集合填充操作。这意味着只能对返回集合中的各个数组进行处理。
  • 21. fetch 例程
  • 22. 子查询如果底层数据库支持子查询,则可以在 HQL 语句中使用子查询,与 SQL 子查询相似的是,HQL 中的子查询也需要使用() From Cat as cat where (cat.name, cat.color) is not in (select c.name, c.color from DomesticCat c)
  • 23. 数据加载方式 在通过JDBC操作数据时,只能通过SQL语句来加载所需要的数据 由于O-R Mapping的帮助,Hibernate总共有4种数据加载方式: 即时加载 延迟加载 预先加载 批量加载
  • 24. 即时加载 即时加载:当实体加载完成后,立即加载该实体所关联的数 据。例如:客户和订单之间的一对多关联映射: 当查询 Customers 实体时,会自动加载它所关联的 Orders 实体对象,因此会出现二条查询语句。 即时加载的基本原理,当宿主实体加载时,会立即自动加载 关联的实体对象,并完成关联实体对象的属性填充和实体对 象的构造。
  • 25. 延迟加载 即时加载中,当加载 Customers 对象时,通过另一条查询 语句自动加载了它所关联的实体对象,但是如果只需要 Customers 对象数据,而不需要它所关联的 Orders 对象 数据,就造成了性能的损耗。延迟加载机制就是为了解决 这个问题。 当查询 Customers 对象时,并没有立即加载它所关联的 Orders 对象,只有执行确实获取关联的 Orders 对象数据 时,才会发起对关联对象的查询。 延迟加载机制,只有当确实需要获取关联数据时,才去真 正加载关联对象
  • 26. 预先加载 预先加载:与即时加载类似,预先加载时,实体及其关联的对象同时读取,不同的是预先加载只通过一条 SQL 语句(基于外连接[outer join])完成同时读取. 预先加载通过 outer-join 完成关联数据的加载。 对于集合属性不推荐使用。
  • 27.    批量加载 批量加载,通过批量提交多个限定条件,一次完成多个数据的 读取: select * from customer where id=’1’; select * from customer where id=’2’; 将以上两个SQL语句合并: select * from customer where id=’1’ or id=’2’; 当使用批量加载时,Hibernate会自动在当前session中查找是否还有同类型的待加载的实体对象,如果有就将查询条件合并到当前的查询语句中,这样就通过一次数据库操作完成了多次读取任务,从而提高读取性能。 如需启用批量加载,须配置实体类的class元素: batch-size属性:指定批量加载尺寸以及启用批量加载,以上 配置每次最多同时加载5个同类型实体对象。
  • 28. SQL 查询Hibernate 提供了对原生 SQL 以及存储过程的支持,相对于基于 JDBC 的 SQL,Hibernate 提供了更为妥善的封装。在 Hibernate SQL 查询接口中,只需指定别名,而 ResultSet 与实体的映射由 Hibernate 自动完成。 Hibernate SQL 查询是通过 SQLQuery 接口来表示,SQLQuery 接口是 Query 接口的子接口,因此完全可以调用 Query 接口的方法。
  • 29. SQL 查询例程
  • 30. SQL 查询SQLQuery 比 Query 多许多个重载方法: addEntity: 将SQL表的别名和实体类联系起来,确定查询结 果集的形态
  • 31. 命名SQL查询 可以在映射文档中定义查询的名字,然后就可以象调用一个命名的HQL查询一样直接调用命名SQL查询.在这种情况下,不需要调用addEntity()方法,因为在配置文件中已经完成了映射结果与实体类的关联。
  • 32. 分页查询Query接口提供了用于分页显示查询结果的方法: setFirstResult(int firstResult):设定从哪一个对象开始检索,参数firstResult表示这个对象在查询结果中的索引位置,索引位置的起始值为0。默认情况下,Query接口从查询结果中的第一个对象,也就是索引位置为0的对象开始检索。 setMaxResult(int maxResults):设定一次最多检索出的对象数目。默认情况下,Query接口检索出查询结果中所有的对象。
  • 33. 管理Session在利用Hibernate开发DAO模块时,和Session打交道最多,所 以如何合理的管理Session,避免Session的频繁创建和销毁, 对于提高系统的性能来说是非常重要的。 Session是由SessionFactory负责创建的,而SessionFactory 的实现是线程安全的,多个并发的线程可以同时访问一个 SessionFactory并从中获取Session实例,但 Session 却是 线程不安全的。多个线程同时使用一个Session实例进行 CRUD,就有可能导致数据存取的混乱。 建议为每个请求对应一个 Session。为了达到这种效果,推荐 使用一个 ThreadLocal 变量,把 Session 绑定到处理客户端 请求的线程上去。这种方式可以让运行在该线程上的所有代码 轻松的访问 Session
  • 34. HibernateSessionFactory类代码片段
  • 35. ThreadLocalThreadLocal是一个线程隔离(或者说是线程安全)的变量存储 的管理实体(注意:不是存储用的),以Java类方式表现 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变 量的线程提供独立的变量副本,所以每一个线程都可以独立地 改变自己的副本,而不会影响其它线程所对应的副本。 一个ThreadLocal变量类似一个HashMap,它的key集合就是 Thread.currentThread(),它的value集合就是要跨域共享的 对象。当代码从threadLocal变量get()来取对象的时候,就是 以代码运行所在的currentThread为key,去找它对应的value 共享对象。因而在一个thread里面,任何被该thread调用到的 类,方法代码都可以取到同一个跨域共享对象。而不同的 thread则取到不同的对象。
  • 36. ThreadLocalThreadLocal接口的方法: void set(Object value): 设置当前线程的线程局部变量的值。 public Object get():返回当前线程所对应的线程局部变量。 public void remove() 将当前线程局部变量的值删除,目 的是为了减少内存的占用。 protected Object initialValue():返回该线程局部变量 的初始值,该方法是一个protected的方法,是为了让子类 覆盖而设计的。
  • 37. ThreadLocalThreadLocal实现的思路:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本。一个简单的实现版本:
  • 38. ThreadLocal例程
  • 39. 其它话题Hibernate 过滤器 Hibernate 拦截器 Hibernate 监听器
  • 40. 小结HQL 查询: Query 接口 联合查询:fetch 关键字 数据加载方式:延迟加载,批量加载 分页查询 管理 Session:TheadLocal 接口的理解及使用