您的位置:首页 > 其它

hibernate系列十五:hql连接查询,查询性能优化,hql批量增删改

2017-12-01 17:07 417 查看
一 hql连接查询

和SQL查询一样,HQL也支持各种各样的连接查询,如内连接、外连接。我们知道在SQL中可通过join子句实现多表之间的连接查询。HQL同样提供了连接查询机制,还允许显式指定迫切内连接和迫切左外连接。HQL提供的连接方式如表1所示。

连接类型HQL语法适用范围
内连接inner join或 join适用于有关联关系

迫切内连接inner join fetch或 join fetch的持久化类,并且在

左外连接left outer join或 left join映射文件中对这种关

迫切左外连接left outer join fetch或 left join fetch联关系做了映射
右外连接right outer join或 right join 
迫切连接是指在指定连接方式时不仅指定了连接查询方式,而且显式地指定了关联级别的查询策略。Hibernate使用fetch关键字实现,fetch关键字表明“左边”对象用于与“右边”对象关联的属性会立即被初始化。
案例一,多对一关联,无迫切连接

package com.obtk.test2;

import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;

import com.obtk.entitys.DeptEntity;
import com.obtk.entitys.EmployeeEntity;
import com.obtk.utils.HibernateUtil;

public class TestJoin01 {
public static void main(String[] args) {
Session session=null;
String hql="from EmployeeEntity e inner join e.dept d " +
" where e.gender=? and d.deptName=? ";
try {
session=HibernateUtil.getSession();
Query qy=session.createQuery(hql);
qy.setParameter(0, "男");
qy.setParameter(1, "人事部");
List<Object[]> objList=qy.list();
EmployeeEntity theEmp=null;
DeptEntity dept=null;
for(Object[] theArr :objList){
theEmp=(EmployeeEntity)theArr[0];
dept=(DeptEntity)theArr[1];
System.out.println(theEmp.getEmpName()+","+theEmp.getGender()
+","+dept.getDeptName());
}
} catch (HibernateException e) {
e.printStackTrace();
}finally{
HibernateUtil.closeSession();
}
}
}
案例二   多对一关联,有迫切连接(注意fetch关键字)
package com.obtk.test2;

import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;

import com.obtk.entitys.DeptEntity;
import com.obtk.entitys.EmployeeEntity;
import com.obtk.utils.HibernateUtil;

public class TestFetchJoin01 {
public static void main(String[] args) {
Session session=null;
String hql="from EmployeeEntity e inner join fetch e.dept d " +
" where e.gender=? and d.deptName=? ";
try {
session=HibernateUtil.getSession();
Query qy=session.createQuery(hql);
qy.setParameter(0, "男");
qy.setParameter(1, "人事部");
List<EmployeeEntity> empList=qy.list();
for(EmployeeEntity theEmp:empList){
System.out.println(theEmp.getEmpName()+","+theEmp.getGender()
+","+theEmp.getDept().getDeptName());
}
} catch (HibernateException e) {
e.printStackTrace();
}finally{
HibernateUtil.closeSession();
}
}
}
案例三  一对多关联,有迫切连接
package com.obtk.test2;

import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;

import com.obtk.entitys.DeptEntity;
import com.obtk.entitys.EmployeeEntity;
import com.obtk.utils.HibernateUtil;

public class TestFetchJoin02 {
public static void main(String[] args) {
Session session=null;
String hql="select distinct d from DeptEntity d inner join fetch d.empList e " +
" where e.gender=? ";
try {
session=HibernateUtil.getSession();
Query qy=session.createQuery(hql);
qy.setParameter(0, "男");
List<DeptEntity> deptList=qy.list();
List<EmployeeEntity> empList=null;
for(DeptEntity theDept:deptList){
empList=theDept.getEmpList();
for(EmployeeEntity theEmp: empList){
System.out.println(theEmp.getEmpName()+","+theEmp.getGender()
+","+theDept.getDeptName());
}
}
} catch (HibernateException e) {
e.printStackTrace();
}finally{
HibernateUtil.closeSession();
}
}
}
建议用多对一,也就是从外键表发出关联,这样性能会好些,输出的sql会少些。
案例四  隐式内连接

package com.obtk.test2;

import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;

import com.obtk.entitys.EmployeeEntity;
import com.obtk.utils.HibernateUtil;

public class TestYinJoin {
public static void main(String[] args) {
Session session=null;
//隐式内连接
String hql="from EmployeeEntity e where e.gender=? and e.dept.deptName=?";
try {
session=HibernateUtil.getSession();
Query qy=session.createQuery(hql);
qy.setParameter(0, "男");
qy.setParameter(1, "人事部");
List<EmployeeEntity> empList=qy.list();
for(EmployeeEntity theEmp:empList){
System.out.println(theEmp.getEmpName()+","+theEmp.getGender()
+","+theEmp.getDept().getDeptName());
}
} catch (HibernateException e) {
e.printStackTrace();
}finally{
HibernateUtil.closeSession();
}
}
}


案例五,迫切左外连接
package com.obtk.test2;

import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;

import com.obtk.entitys.DeptEntity;
import com.obtk.entitys.EmployeeEntity;
import com.obtk.utils.HibernateUtil;

public class TestLeftJoin01 {
public static void main(String[] args) {
Session session=null;
String hql="from EmployeeEntity e left join fetch e.dept d ";
try {
session=HibernateUtil.getSession();
Query qy=session.createQuery(hql);
List<EmployeeEntity> empList=qy.list();
for(EmployeeEntity theEmp:empList){
if(theEmp.getDept()!=null){
System.out.println(theEmp.getEmpName()+","+theEmp.getGender()
+","+theEmp.getDept().getDeptName());
}else{
System.out.println(theEmp.getEmpName()+","+theEmp.getGender()
+",null");
}

}
} catch (HibernateException e) {
e.printStackTrace();
}finally{
HibernateUtil.closeSession();
}
}
}
fetch关键字只对inner join和left join有效。对于right join而言,由于作为关联对象容器的“左边”对象可能为null,所以也就无法通过fetch关键字强制Hibernate进行集合填充操作。

二  查询性能优化

 1.Hibernate主要从以下几方面来优化查询性能

    (1)使用迫切左外连接或迫切内连接查询策略、查询缓存等方式,减少select语句的数目,降低访问数据库的频率。

    (2)使用延迟查询策略等方式避免加载多余的不需要访问的数据。

    (3)使用Query接口的iterate()方法减少select语句中的字段,从而降低访问数据库的数据量。

    Query接口的iterate()方法和list()方法都用来执行SQL查询语句。在某些情况下,iterate()方法能提高查询性能。如示例1和示例2所示,先查询所有学生信息,再查询符合条件的学生信息,这种情况下,对比list()方法和iterate()方法的查询性能。

示例l

   List<StudentEntity>stuList=session.createQuery("from StudentEntity").list();

   for(StudentEntity student: stuList){

        System.out.println(student.getStuName());

   }

   stuList=session.createQuery("fromStudentEntity where stuId<2020").list();

   for(StudentEntity student: stuList){

       System.out.println(student.getStuName());

   }

运行示例l,Hibernate执行的select语句:

   select * from StudentEntity

   select * from StudentEntity wherestuId<2020

 

    第一次使用list()方法查询时,Hibernate从数据库中查询StudentEntity对象,把所有的StudentEntity对象放入Session缓存中;第二次使用list()查询时,Hibernate仍然从数据库中查询StudentEntity对象,而不是从Session缓存中获取StudentEntity对象。使用iterate()方法,能提高查询性能,如示例2所示。

示例2

List<StudentEntity>stuList=session.createQuery("from StudentEntity").list();

for(StudentEntitystudent: stuList){

       System.out.println(student.getStuName());

}

Iterator<StudentEntity>studentIt= session.createQuery("from StudentEntity wherestuId<2020").iterate();

StudentEntitystudent=null;

while(studentIt.hasNext()){

   student= studentIt.next();

   System.out.println(student.getStuName());

}

 

运行示例2,Hibernate执行的select语句:

   select * from StudentEntity

   select * from StudentEntity wherestuId<2020

 

    第一次使用list()方法查询时,Hibernate从数据库中查询StudentEntity对象,把所有的StudentEntity对象放入Session缓存中;第二次使用iterate()方法查询时,首先查询ID字段,然后根据ID字段到Hibernate的Session缓存中查找匹配的StudentEntity对象。如果存在,就直接把它加入到查询结果集中,否则就执行额外的select语句,根据ID字段到数据库中查询对象。

    iterate()方法适用于查询对象开启二级缓存的情况。

 2.HQL优化

    HQL优化是Hibernate程序性能优化的一个方面,HQL的语法与SQL非常类似。HQL是基于SQL的,只是增加了面向对象的封装。如果抛开HOL同Hibernate本身一些缓存机制的关联,HQL的优化技巧同SQL的优化技巧一样。在编写HQL时,需注意以下几个原则。

    (1)避免or操作的使用不当。如果where子句中有多个条件,并且其中某个条件没有索引,使用or,将导致全表扫描。假定在HOUSE表中TITLE有索引,PRICE没有索引,执行以下HQL语句:

    from House   where title= ‘出租-居室’  or price<1500

    当PRICE比较时,会引起全表扫描。

    (2)避免使用not。如果where子句的条件包含not关键字,那么执行时该字段的索引失效。这些语句需要分成不同情况区别对待,如查询租金不多于1800元的店铺出租转让信息的HQL语句:

    from House as h where not (h.price>1800)

    对于这种不大于(不多于)、不小于(不少于)的条件,建议使用比较运算符来替代not,如不大于就是小于等于。例如:

    from House as h where h.price<=1800

    如果知道某一字段所允许的设置值,那么就有其他的解决方法。例如,在用户表中增加性别字段,规定性别字段仅能包含M和F,当要查询非男用户时,为避免使用not关键字,将条件设定为查询女用户即可。

    (3)避免like的特殊形式。某些情况下,会在where子句条件中使用like。如果like以一个“%” 或“_”开始即前模糊,则该字段的索引不起作用。但是非常遗憾的是,对于这种问题并没有额外的解决方法,只能通过改变索引字段的形式变相地解决。

    (4)避免having予句。在分组的查询语句中,可在两个位置指定条件,一是where子旬中,二是在having子句中。尽可能地在where子句而不是having子句中指定条件。Having是在检索出所有记录后才对结果集进行过滤,这个处理需要一定的开销,而where子句限制记录数目,能减少这方面的开销。

    (5)避免使用distinct。指定distinct会导致在结果中删除重复的行。这会对处理时间造成一定的影响,因此在不要求或允许冗余时,应避免使用distinct。

    (6)索引在以下情况下失效,应注意使用。

Ø 只要对字段使用函数,该字段的索引将不起作用,如substring(aa,1,2)='xx'。

Ø 只要对字段进行计算,该字段的索引将不起作用,如price+10。

三  hql批量增删改

批量处理数据是指在一个事务场景中处理大量数据。
HQL可以查询数据,也可以批量插入、更新和删除数据。HQL批量操作实际上直接在数据库中完成,处理的数据不需要加载至Session缓存中。使用Query接口的executeUpdate()方法执行用于插入、更新和删除的HQL语句。

案例一  批量添加

package com.obtk.test03;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.obtk.utils.HibernateUtil;

public class TestAdd {
public static void main(String[] args) {
Session session=null;
Transaction tx=null;
String hql="insert into UserEntity(userName,passWord,email) " +
" select userName,passWord,email from UserEntity";
try {
session=HibernateUtil.getSession();
tx=session.beginTransaction();
Query qy=session.createQuery(hql);
int result=qy.executeUpdate();
System.out.println("fdsa:"+result);
tx.commit();
} catch (HibernateException e) {
tx.rollback();
e.printStackTrace();
}finally{
HibernateUtil.closeSession();
}
}
}
案例二   批量删除
package com.obtk.test03;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.obtk.utils.HibernateUtil;

public class TestDelete {
public static void main(String[] args) {
Session session=null;
Transaction tx=null;
String hql="delete from UserEntity where userId>?";
try {
session=HibernateUtil.getSession();
tx=session.beginTransaction();
Query qy=session.createQuery(hql);
qy.setParameter(0, 7);
int result=qy.executeUpdate();
System.out.println("fdsa:"+result);
tx.commit();
} catch (HibernateException e) {
tx.rollback();
e.printStackTrace();
}finally{
HibernateUtil.closeSession();
}
}
}
案例三  批量修改
package com.obtk.test03;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.obtk.utils.HibernateUtil;

public class TestUpdate {
public static void main(String[] args) {
Session session=null;
Transaction tx=null;
String hql="update UserEntity set passWord=? ";
try {
session=HibernateUtil.getSession();
tx=session.beginTransaction();
Query qy=session.createQuery(hql);
qy.setParameter(0, "321");
int result=qy.executeUpdate();
System.out.println("fdsa:"+result);
tx.commit();
} catch (HibernateException e) {
tx.rollback();
e.printStackTrace();
}finally{
HibernateUtil.closeSession();
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐