HQL连接查询和注解

1.HQL各种连接查询
连接类型 HQL语法
内连接 [inner] join
迫切内连接 [inner] join fetch
左外连接 left [outer] join
迫切左外连接 left [outer] join fetch
右外连接 right [outer] join
迫切连接:不仅指定连接查询方式,而且显式指定了关联级别的查询策略,使用fetch关键字,
fetch关键字表明”左边”对象与“右边”对象关联的属性立即会被初始化,
对inner join和left outer join有效,如果右联左边可能为null,无法fetch强制进行集合填充
1.1内链接:返回的是Object[]数组

public static void testInner() {
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
try {
//有关联关系的2个类,可内联查询
//相当于:select d.* ,e.* from dept d inner join emp e on d.deptno = e.deptno;
List<Object[]> list = session.createQuery(“from Dept d inner join d.emps”).list();

        //返回的是一个Object[]数组,返回了dept,emp 2个对象
		for (Object[] objects : list) {
			Dept dept = (Dept) objects[0];
			Emp emp = (Emp) objects[1];
			System.out.println(dept.getDname()+"_"+emp.getEname());
		}
		tx.commit();
	} catch (Exception e) {
		e.printStackTrace();
		tx.rollback();
	}
}

1.2迫切连接:返回from后面的对象,关联对象抓取填充到了集合
执行的还是:select * from dept d inner join emp e on d.deptno = e.deptno;
只是因为多了fetch关键字,会将emp的数据抓出来,填充到Dept集合emps中
public static void testFetchInner() {
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
try {
// inner join fetch迫切连接,fetch将后面的对象抓取填空到集合中
List list = session.createQuery(
“select distinct d from Dept d inner join fetch d.emps”).list();
// 返回的是一个对象Dept,Emp被填空到Dept集合中
for (Dept dept : list) {
System.out.println(dept.getDname());
//循环获取员工
for (Emp emp : dept.getEmps()) {
System.out.print("\t"+emp.getEname()+" “);
}
System.out.println(”\r\n----------------");
}
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
}
}
注意:若没有select distinct d取出来的数据因为有多个员工,部门会重复:

添加去除重复关键字后:

1.3外连接(左连接和右连接)
1.左外连接,以左表为基础,不使用fetch返回object[], 使用fetch返回一个对象
问:为什么可以直接通过from Emp 获取员工之后,就可以获取部门,为什么还要自己写连接
答:程序查询部门是通过员工的外键deptno去查询,每次获取一次查询一次,N+1条SQL
通过手写连接,可一次性查询出所有的记录
//左连接
public static void testLeftJoin() {
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
try {
//以前的这种代码,是依靠程序去查询,通过emp的deptno外键再去查询Dept表,
//产生N+1条SQL语句效率低
// List list =session.createQuery(“from Emp”).list();
// for (Emp emp : list) {
// System.out.print(emp.getEname());//
// if(emp.getDept()!=null) {//有部门输出部门
// System.out.print(",部门"+emp.getDept().getDname());
// }else{
// System.out.print(",部门为空");
// }
// System.out.println("");
// }

		//一条SQL语句查询结果
        List<Object[]> list = session.createQuery("from Emp e left join e.dept").list();

		// 返回的是一个Object[]数组,返回了dept,emp 2个对象
		for (Object[] objs : list) {				
			System.out.println(objs[0]+"---------"+objs[1]);
		}
		tx.commit();
	} catch (Exception e) {
		e.printStackTrace();
		tx.rollback();
	}
}

//左迫切连接,将fetch后面的对象填充, 返回的是对象
public static void testFetchLeftJoin() {
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
try {
// 有关联关系的2个类,可内联查询
List list = session.createQuery(
“from Emp e left join fetch e.dept”).list();

		// 返回的是一个Object[]数组,返回了dept,emp 2个对象
		for (Emp emp : list) {
			System.out.print(emp.getEname());
			if(emp.getDept()!=null){
				System.out.print(",部门:"+emp.getDept().getDname());
			}else{
				System.out.print(",部门为空");
			}
			System.out.println("");
		}
		tx.commit();
	} catch (Exception e) {
		e.printStackTrace();
		tx.rollback();
	}
}

2.右外连接,以右表为基础,不可使用fetch,因左边可能null,无法赋值,很少使用忽略
1.4等值连接 : 相当于以前的select * from a,b where a.id=b.aid
两个类之间没有建立任何关联关系,通过属性进行筛选
from Dept d ,Emp e where d = e.dept;
注意:如果没有where条件筛选,返回的是2个表的记录数之积,也就是笛卡尔集
如A有12条数据,B有4条件,那么就是12*4=48条数据
1.5隐式内连接

public static void testImplict() {
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
try {
//相当于:select e.* from EMP e, DEPT d where e.deptno=d.DEPTNO and d.DNAME=‘SALES’;
List list = session.createQuery(
“from Emp e where e.dept.dname=?”).setString(0, “SALES”).list();

		for (Emp emp : list) {
			System.out.println( emp.getEname()+","+emp.getDept().getDname());
		}
		tx.commit();
	} catch (Exception e) {
		e.printStackTrace();
		tx.rollback();
	}
}

1.6内连接和迫切内连接的区别
内链接返回的是object数组对象,里面存储的是结果集中返回的多个对象
迫切内连接返回的是from后面的对象,将fetch关键字后面的对象读取填空到from后面的对象中
示例:from Dept d inner join fetch d.emps 将emp表中数据填充到Dept的集合emps中,返回Dept
2.分组统计数据
2.1聚合函数:count,sum,min,max,avg[不能与返回多行的列一起使用]
public static void main(String[] args) {
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
try {
// 结果集只有一列,返回Object对象
Object obj = session.createQuery(“select count(deptno) from Dept”)
.uniqueResult();
// 若不知道返回的类型是什么,可使用此方法查看
System.out.println(“obj:”+obj+"----"+obj.getClass().getName());

		// 结果集超过一列,返回Object数组
		Object[] objs = (Object[]) session.createQuery(
				"select count(deptno),max(deptno) from Dept").uniqueResult();
		System.out.println(objs[0]+","+objs[1]);
		
		tx.commit();
	} catch (Exception e) {
		e.printStackTrace();
		tx.rollback();
	}
}

2.2分组查询,group by ,having
使用group by,select语句中只能是聚合函数或者group by后面的表达式
public static void main(String[] args) {
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
try {
// 结果集只有一列,返回Object对象
List<Object[]> list
= session.createQuery(“select count(*),job from Emp group by job”).list();

		for (Object[] objects : list) {
			long count = (long) objects[0];
			String job = (String) objects[1];
			System.out.println("count:"+count+",job:"+job);
		}
		tx.commit();
	} catch (Exception e) {
		e.printStackTrace();
		tx.rollback();
	}
}

找出工作人数超过3个的,修改HQL语句:
List<Object[]> list = session.createQuery(“select count(empno),job from Emp group by job having count(empno)>=3”).list();
由于每次返回Object数组,不方便遍历数据,可定义实体封装获取的属性
package cn.entity;
public class JobCount {
private long count;//取决于查询的结果
private String job;
public JobCount(long count, String job) {//定义构造用以封装数据
this.count = count;
this.job = job;
}
/* 省略get和set */
}
示例更改为:
public static void main(String[] args) {
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
try {
// 将结果封装到对象中,返回对象,翻看前面投影查询
List list = session.createQuery(“select new cn.entity.JobCount(count(empno),job) from Emp group by job having count(empno)>=3”).list();

for (JobCount jobCount : list) { System.out.println(“count:”+jobCount.getCount()+",job:"+jobCount.getJob());
}
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
}
}
3.子查询: 应用在HQL查询语句的where子句中
3.1all:返回的所有记录
示例:查询所有员工工资都小于5000的部门
以前: select distinct deptno from emp where deptno not in (
select distinct deptno from emp where nvl(sal,0)>=5000)
现在:session.createQuery(
“from Dept d where 5000>all(select nvl(e.sal,0) from d.emps e)”).list();
3.2any:返回的任意一条记录
3.3some:和“any”意思相同
示例:查询至少有一个员工工资 < 5000
以前:select * from dept dt where deptno in (
select distinct deptno from emp e where nvl(e.sal,0)<5000 );
现在:session.createQuery(
“from Dept d where 5000>any(select nvl(e.sal,0) from d.emps e)”).list();
3.4in:与“=any”意思相同 ,就是与返回的任何一条记录相等
示例:查询有一个员工工资 =5000
以前:select * from dept dt where deptno in (
select distinct deptno from emp where nvl(sal,0)=5000 );
现在:session.createQuery(
“from Dept d where 5000 in (select nvl(e.sal,0) from d.emps e)”).list();
相同效果
“from Dept d where 5000 =any(select nvl(e.sal,0) from d.emps e)”).list();
“from Dept d where 5000 =some(select nvl(e.sal,0) from d.emps e)”).list();
3.5exists:至少返回一条记录
示例:至少有一名员工的部门
以前:select * from dept where deptno in
(select distinct deptno from emp e where deptno is not null );
现在:session.createQuery(“from Dept d where exists (from d.emps)”).list();

3.6HQL提供了操作集合的函数或属性
size() 或size 获取集合中元素的数目
minIndex()或minIndex 对于建立了索引的集合,获得最小的索引
maxIndex()或maxIndex 对于建立了索引的集合,获得最大的索引
minElement()或minElement 对于包含基本类型元素的集合,获取最小值元素
maxElement()或maxElement 对于包含基本类型元素的集合,获取最大值元素
elements() 获取集合中的所有元素

示例:查询指定7499员工所在部门
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
try {
//定义一个员工,如果编号存在,返回部门名称,不存在或者没有部门不输出
Emp emp = new Emp();
emp.setEmpno(7499);

		//方式1:查询员工对应的部门 使用elements
		List<Dept> list = session.createQuery(

“from Dept d where ? in elements( d.emps)”).setParameter(0, emp).list();
//方式2:查询员工对应的部门,使用from d.emps 效果相同
List list = session.createQuery(
“from Dept d where ? in (from d.emps)”).setParameter(0, emp).list();
for (Dept dept : list) {
System.out.println(dept.getDname());
}
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
}
示例:查询部门中员工数量>3的部门
以前: select * from dept where deptno in
(select deptno from emp where deptno is not null group by deptno having count(*)>=4)
现在: session.createQuery(“from Dept d where d.emps.size>=4”).list();
session.createQuery(“from Dept d where size(d.emps)>5”).list();

4.查询性能优化
Hibernate查询优化策略
使用延迟加载等方式避免加载多余数据
通过使用连接查询,配置二级缓存、查询缓存等方式减少select语句数目
结合缓存机制,使用iterate()方法减少查询字段数及数据库访问次数
对比list()方法和iterate()方法
HQL优化
注意避免or、not、like使用不当导致的索引失效
注意避免having子句、distinct导致的开销
注意避免对索引字段使用函数或进行计算导致的索引失效
5.在Hibernate中使用注解
5.1使用注解配置持久化类 及 对象关联关系
1.注解配置持久化类
@Entity 将一个类声明为一个持久化类,在类上声明,
默认所有的属性都会映射到数据库成同名字段,可使用注解忽略
@Table 为持久化类映射指定表
@Id 声明了持久化类的标识属性
@GeneratedValue 定义标识属性值的生成策略
@SequenceGenerator 定义序列生产器
@Column 将属性映射到列(字段)
@Transient 将忽略这些属性

2.注解配置关联关系
@OneToOne 建立持久化类之间的一对一关联关系
@OneToMany 建立持久化类之间的一对多关联关系
@ManyToOne 建立持久化类之间的多对一关联关系
@JoinColumn 和@ManyToOne配合,指定外键列
@ManyToMany 建立持久化类之间的多对多关联关系
cascade属性: 指定级联操作的行为(可多选)
CascadeType.PERSIST 级联新增(又称级联保存):
CascadeType.MERGE 级联合并(又称级联更新)
CascadeType.REMOVE 级联删除
CascadeType.REFRESH 级联刷新
CascadeType.ALL 包含所有持久化方法
通过fetch属性指定加载方式,有两个值:
FetchType.LAZY:延迟加载
FetchType.EAGER:急加载

3.

4.示例,一对多和多对一:
@Entity
@Table(name = “huser”)
public class User {
@Id
@Column(name = “id”)
@Id
@GeneratedValue(generator = “myGer”)
//自定义方式
//@GenericGenerator(name=“myGer”,strategy=“assigned”)
// 自动增长
@GenericGenerator(name=“myGer”,strategy=“increment”)
//序列方式
//@GenericGenerator(name = “myGer”, strategy = “sequence”,
parameters = { @Parameter(name = “sequence”, value = “seq_grade”) })

private int uid;

@Column(name = "name")
private String uname;
@Column(name = "age")
private int age;
@Column(name = "birthday")
private Date birthday;

@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="tid")
private Teacher teacher;

@Transient  
private Date hireDate;//不会在数据库生成

//省略get或者set
}

@Entity
@Table(name = “hteacher”)
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = “seq_teacher”)
@SequenceGenerator(name = “seq_teacher”, sequenceName = “seq_grade”)
private int tid;

@Column(name = "tname")
private String tname;

@OneToMany(mappedBy="teacher",cascade=CascadeType.ALL)
private Set<User> users = new HashSet<User>();

public Set<User> getUsers() {
	return users;
}

//省略get或者set
}

测试:
public static void main(String[] args) {
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
try {
Teacher t = new Teacher();
t.setTname(“芬姐” );

		User user = new User("张1",20,new Date());

//没有update,一定要关联 跟映射是一样 inverse=“true”
user.setTeacher(t);
User user2 = new User(“张2”,21,new Date());
user2.setTeacher(t);
t.getUsers().add(user);
t.getUsers().add(user2);
session.save(t);
System.out.println(t.getTid());
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
}
}
5.示例,多对多:
Teacher:
@ManyToMany(cascade=CascadeType.ALL)
@JoinTable(name=“tutable”,joinColumns={@JoinColumn(name=“tid”)},
inverseJoinColumns={@JoinColumn(name=“id”)})
private Set users = new HashSet();

User:
@ManyToMany(mappedBy=“users”,fetch=FetchType.LAZY)
private Set teachers = new HashSet();

6.主键策略
@Id
@GeneratedValue(generator = “myGer”)
//自定义方式
//@GenericGenerator(name=“myGer”,strategy=“assigned”)
// 自动增长
@GenericGenerator(name=“myGer”,strategy=“increment”)
//序列方式
//@GenericGenerator(name = “myGer”, strategy = “sequence”,
parameters = { @Parameter(name = “sequence”, value = “seq_grade”) })

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值