1. Hibernate提供了以下几种检索对象的方式:

    • 导航对象图检索方式: 根据已经加载的对象导航到其他对象。

    • OID 检索方式: 按照对象的OID来检索对象。

    • HQL 检索方式: 使用面向对象的 HQL 查询语言。

    • QBC 检索方式: 使用QBC(QueryBy Criteria) API 来检索对象. 这种API封装了基于字符串形式的查询语句,提供了更加面向对象的查询接口。

    • 本地SQL检索方式:使用本地数据库的SQL查询语句。

  2. HQL(HibernateQuery Language) 是面向对象的查询语言, 它和SQL查询语言有些相似.在Hibernate提供的各种检索方式中,HQL 是使用最广的一种检索方式.它有如下功能:

    • 在查询语句中设定各种查询条件。
    • 支持投影查询,即仅检索出对象的部分属性。
    • 支持分页查询。
    • 支持连接查询。
    • 支持分组查询,允许使用HAVING和GROUPBY 关键字。
    • 提供内置聚集函数,如sum(),min() 和 max()。
    • 支持子查询。
    • 支持动态绑定参数。
    • 能够调用用户定义的 SQL 函数或标准的SQL函数。
  3. HQL检索方式包括以下步骤:

    • 通过Session的createQuery()方法创建一个Query对象,它包括一个HQL查询语句.HQL 查询语句中可以包含命名参数。
    • 动态绑定参数。
    • 调用Query相关方法执行查询语句。
  4. 测试用例

    	@Test
    	public void testBatch(){
    		session.doWork(new Work() {			
    			@Override
    			public void execute(Connection connection) throws SQLException {
    				//通过 JDBC 原生的 API 进行操作, 效率最高, 速度最快!
    			}
    		});
    	}
    	
    	@Test
    	public void testManageSession(){
    		
    		//获取 Session
    		//开启事务
    		Session session = HibernateUtils.getInstance().getSession();
    		System.out.println("-->" + session.hashCode());
    		Transaction transaction = session.beginTransaction();
    		
    		DepartmentDao departmentDao = new DepartmentDao();
    		
    		Department dept = new Department();
    		dept.setName("ATGUIGU");
    		
    		departmentDao.save(dept);
    		departmentDao.save(dept);
    		departmentDao.save(dept);
    		
    		//若 Session 是由 thread 来管理的, 则在提交或回滚事务时, 已经关闭 Session 了. 
    		transaction.commit();
    		System.out.println(session.isOpen()); 
    	}
    	
    	@Test
    	public void testQueryIterate(){
    		Department dept = (Department) session.get(Department.class, 70);
    		System.out.println(dept.getName());
    		System.out.println(dept.getEmps().size()); 
    		
    		Query query = session.createQuery("FROM Employee e WHERE e.dept.id = 80");
    //		List<Employee> emps = query.list();
    //		System.out.println(emps.size()); 
    		
    		Iterator<Employee> empIt = query.iterate();
    		while(empIt.hasNext()){
    			System.out.println(empIt.next().getName()); 
    		}
    	}
    	
    	@Test
    	public void testUpdateTimeStampCache(){
    		Query query = session.createQuery("FROM Employee");
    		query.setCacheable(true);
    		
    		List<Employee> emps = query.list();
    		System.out.println(emps.size());
    		
    		Employee employee = (Employee) session.get(Employee.class, 100);
    		employee.setSalary(30000);
    		
    		emps = query.list();
    		System.out.println(emps.size());
    	}
    	
    	@Test
    	public void testQueryCache(){
    		Query query = session.createQuery("FROM Employee");
    		query.setCacheable(true);
    		
    		List<Employee> emps = query.list();
    		System.out.println(emps.size());
    		
    		emps = query.list();
    		System.out.println(emps.size());
    		
    		Criteria criteria = session.createCriteria(Employee.class);
    		criteria.setCacheable(true);
    	}
    	
    	@Test
    	public void testCollectionSecondLevelCache(){
    		Department dept = (Department) session.get(Department.class, 80);
    		System.out.println(dept.getName());
    		System.out.println(dept.getEmps().size()); 
    		
    		transaction.commit();
    		session.close();
    		
    		session = sessionFactory.openSession();
    		transaction = session.beginTransaction();
    		
    		Department dept2 = (Department) session.get(Department.class, 80);
    		System.out.println(dept2.getName());
    		System.out.println(dept2.getEmps().size()); 
    	}
    	
    	@Test
    	public void testHibernateSecondLevelCache(){
    		Employee employee = (Employee) session.get(Employee.class, 100);
    		System.out.println(employee.getName()); 
    		
    		transaction.commit();
    		session.close();
    		
    		session = sessionFactory.openSession();
    		transaction = session.beginTransaction();
    		
    		Employee employee2 = (Employee) session.get(Employee.class, 100);
    		System.out.println(employee2.getName()); 
    	}
    	
    	@Test
    	public void testHQLUpdate(){
    		String hql = "DELETE FROM Department d WHERE d.id = :id";
    		
    		session.createQuery(hql).setInteger("id", 280)
    		                        .executeUpdate();
    	}
    	
    	@Test
    	public void testNativeSQL(){
    		String sql = "INSERT INTO gg_department VALUES(?, ?)";
    		Query query = session.createSQLQuery(sql);
    		
    		query.setInteger(0, 280)
    		     .setString(1, "ATGUIGU")
    		     .executeUpdate();
    	}
    	
    	@Test
    	public void testQBC4(){
    		Criteria criteria = session.createCriteria(Employee.class);
    		
    		//1. 添加排序
    		criteria.addOrder(Order.asc("salary"));
    		criteria.addOrder(Order.desc("email"));
    		
    		//2. 添加翻页方法
    		int pageSize = 5;
    		int pageNo = 3;
    		criteria.setFirstResult((pageNo - 1) * pageSize)
    		        .setMaxResults(pageSize)
    		        .list();
    	}
    	
    	@Test
    	public void testQBC3(){
    		Criteria criteria = session.createCriteria(Employee.class);
    		
    		//统计查询: 使用 Projection 来表示: 可以由 Projections 的静态方法得到
    		criteria.setProjection(Projections.max("salary"));
    		
    		System.out.println(criteria.uniqueResult()); 
    	}
    	
    	@Test
    	public void testQBC2(){
    		Criteria criteria = session.createCriteria(Employee.class);
    		
    		//1. AND: 使用 Conjunction 表示
    		//Conjunction 本身就是一个 Criterion 对象
    		//且其中还可以添加 Criterion 对象
    		Conjunction conjunction = Restrictions.conjunction();
    		conjunction.add(Restrictions.like("name", "a", MatchMode.ANYWHERE));
    		Department dept = new Department();
    		dept.setId(80);
    		conjunction.add(Restrictions.eq("dept", dept));
    		System.out.println(conjunction); 
    		
    		//2. OR
    		Disjunction disjunction = Restrictions.disjunction();
    		disjunction.add(Restrictions.ge("salary", 6000F));
    		disjunction.add(Restrictions.isNull("email"));
    		
    		criteria.add(disjunction);
    		criteria.add(conjunction);
    		
    		criteria.list();
    	}
    	
    	@Test
    	public void testQBC(){
    		//1. 创建一个 Criteria 对象
    		Criteria criteria = session.createCriteria(Employee.class);
    		
    		//2. 添加查询条件: 在 QBC 中查询条件使用 Criterion 来表示
    		//Criterion 可以通过 Restrictions 的静态方法得到
    		criteria.add(Restrictions.eq("email", "SKUMAR"));
    		criteria.add(Restrictions.gt("salary", 5000F));
    		
    		//3. 执行查询
    		Employee employee = (Employee) criteria.uniqueResult();
    		System.out.println(employee); 
    	}
    	
    	@Test
    	public void testLeftJoinFetch2(){
    		String hql = "SELECT e FROM Employee e INNER JOIN e.dept";
    		Query query = session.createQuery(hql);
    		
    		List<Employee> emps = query.list();
    		System.out.println(emps.size()); 
    		
    		for(Employee emp: emps){
    			System.out.println(emp.getName() + ", " + emp.getDept().getName());
    		}
    	}
    	
    	@Test
    	public void testLeftJoin(){
    		String hql = "SELECT DISTINCT d FROM Department d LEFT JOIN d.emps";
    		Query query = session.createQuery(hql);
    		
    		List<Department> depts = query.list();
    		System.out.println(depts.size());
    		
    		for(Department dept: depts){
    			System.out.println(dept.getName() + ", " + dept.getEmps().size()); 
    		}
    		
    //		List<Object []> result = query.list(); 
    //		result = new ArrayList<>(new LinkedHashSet<>(result));
    //		System.out.println(result); 
    //		
    //		for(Object [] objs: result){
    //			System.out.println(Arrays.asList(objs));
    //		}
    	}
    	
    	@Test
    	public void testLeftJoinFetch(){
    //		String hql = "SELECT DISTINCT d FROM Department d LEFT JOIN FETCH d.emps";
    		String hql = "FROM Department d INNER JOIN FETCH d.emps";
    		Query query = session.createQuery(hql);
    		
    		List<Department> depts = query.list();
    		depts = new ArrayList<>(new LinkedHashSet(depts));
    		System.out.println(depts.size()); 
    		
    		for(Department dept: depts){
    			System.out.println(dept.getName() + "-" + dept.getEmps().size());
    		}
    	}
    	
    	@Test
    	public void testGroupBy(){
    		String hql = "SELECT min(e.salary), max(e.salary) "
    				+ "FROM Employee e "
    				+ "GROUP BY e.dept "
    				+ "HAVING min(salary) > :minSal";
    		
    		Query query = session.createQuery(hql)
    				             .setFloat("minSal", 8000);
    		
    		List<Object []> result = query.list();
    		for(Object [] objs: result){
    			System.out.println(Arrays.asList(objs));
    		}
    	}
    	
    	@Test
    	public void testFieldQuery2(){
    		String hql = "SELECT new Employee(e.email, e.salary, e.dept) "
    				+ "FROM Employee e "
    				+ "WHERE e.dept = :dept";
    		Query query = session.createQuery(hql);
    		
    		Department dept = new Department();
    		dept.setId(80);
    		List<Employee> result = query.setEntity("dept", dept)
    				                     .list();
    		
    		for(Employee emp: result){
    			System.out.println(emp.getId() + ", " + emp.getEmail() 
    					+ ", " + emp.getSalary() + ", " + emp.getDept());
    		}
    	}
    	
    	@Test
    	public void testFieldQuery(){
    		String hql = "SELECT e.email, e.salary, e.dept FROM Employee e WHERE e.dept = :dept";
    		Query query = session.createQuery(hql);
    		
    		Department dept = new Department();
    		dept.setId(80);
    		List<Object[]> result = query.setEntity("dept", dept)
    				                     .list();
    		
    		for(Object [] objs: result){
    			System.out.println(Arrays.asList(objs));
    		}
    	}
    	
    	@Test
    	public void testNamedQuery(){
    		Query query = session.getNamedQuery("salaryEmps");
    		
    		List<Employee> emps = query.setFloat("minSal", 5000)
    				                   .setFloat("maxSal", 10000)
    				                   .list();
    		
    		System.out.println(emps.size()); 
    	}
    	
    	@Test
    	public void testPageQuery(){
    		String hql = "FROM Employee";
    		Query query = session.createQuery(hql);
    		
    		int pageNo = 22;
    		int pageSize = 5;
    		
    		List<Employee> emps = 
    								query.setFirstResult((pageNo - 1) * pageSize)
    								     .setMaxResults(pageSize)
    								     .list();
    		System.out.println(emps);
    	}
    	
    	@Test
    	public void testHQLNamedParameter(){
    		
    		//1. 创建 Query 对象
    		//基于命名参数. 
    		String hql = "FROM Employee e WHERE e.salary > :sal AND e.email LIKE :email";
    		Query query = session.createQuery(hql);
    		
    		//2. 绑定参数
    		query.setFloat("sal", 7000)
    		     .setString("email", "%A%");
    		
    		//3. 执行查询
    		List<Employee> emps = query.list();
    		System.out.println(emps.size());  
    	}
    	
    	@Test
    	public void testHQL(){
    		
    		//1. 创建 Query 对象
    		//基于位置的参数. 
    		String hql = "FROM Employee e WHERE e.salary > ? AND e.email LIKE ? AND e.dept = ? "
    				+ "ORDER BY e.salary";
    		Query query = session.createQuery(hql);
    		
    		//2. 绑定参数
    		//Query 对象调用 setXxx 方法支持方法链的编程风格.
    		Department dept = new Department();
    		dept.setId(80); 
    		query.setFloat(0, 6000)
    		     .setString(1, "%A%")
    		     .setEntity(2, dept);
    		
    		//3. 执行查询
    		List<Employee> emps = query.list();
    		System.out.println(emps.size());  
    	}
    }