紧接着上一篇,今天继续hibernate的学习总结,来聊一聊hibernate的基本查询方法,先说说HQL(hibernate Query Language):它是官方推荐的查询语言。在开始写代码之前,看看需要做哪些准备工作吧,首先,在我们的学生类中新增一个属性“clazz”,其实不加也可以,接着,我们需要重写Student.java类中的toString()方法,代码如下:
/** * 重写toString方法 */ @Override public String toString() { return "Student [age=" + age + ", id=" + id + ", stuName=" + name+ ",clazz="+clazz+"]"; }
再往后,我们需要把关于开启事务、关闭事务、打开session、关闭session之类动作进行封装,为此,在src目录下新建一个包com.joe.util,并在该包下新建一个HibernateUtils.java文件,统一封装如下代码:
package com.joe.util; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; /** * * @author Joe * 工具类 */ public class HibernateUtils { private static SessionFactory sessionFactory; private static Session session; static{ Configuration cfg=new Configuration().configure(); StandardServiceRegistryBuilder ssrb=new StandardServiceRegistryBuilder().applySettings(cfg.getProperties()); ServiceRegistry service=ssrb.build(); sessionFactory=cfg.buildSessionFactory(service); } /** * 无参的构造函数 */ private HibernateUtils(){ } /** * 获取session对象 */ public static Session getSession(){ return sessionFactory.openSession(); } /** * 关闭session对象 */ public static void closeSession(){ if(session!=null&&session.isOpen()){ session.close(); } } /** * 重载关闭session对象方法 * @param session Session对象 */ public static void closeSession(Session session){ if(session!=null&&session.isOpen()){ session.close(); } } }
最后,在项目中新建一个HQLTest.java文件,开始我们的查询HQL查询之旅。
Query接口
Query是Hibernate专门用来执行HQL语句的查询接口,使用方式:
Query query = session.createQuery("HQL语句");
query.setParameter(...);
List resultList = query.list();
1、查询所有实例对象:
/** * 查询所有实例对象 */ @Test public void selectAll() { Transaction tx = null; Session session = null; try { session = HibernateUtils.getSession(); tx = session.beginTransaction(); String hql = " from Student"; Query query = session.createQuery(hql); @SuppressWarnings("unchecked") List<Student> list = (List<Student>) query.list(); for (Student stu : list) { System.out.println(stu); } tx.commit(); } catch (HibernateException he) { // TODO: handle exception if (tx != null) { tx.rollback(); } he.printStackTrace(); } finally { HibernateUtils.closeSession(session); } }
这里的String hql = " from Student";,这里的Student就是我们的实体类名,当然,也可以这样写:
String hql = " select stu from Student as stu"; //as也可以省略,直接写成 //String hql = " select stu from Student stu";
2、查询单个实体对象:
/** * 查询单个实例对象 */ @Test public void selectSingle() { Transaction tx = null; Session session = null; try { session = HibernateUtils.getSession(); tx = session.beginTransaction(); String hql = " from Student"; Student stu = (Student) session.createQuery(hql).setMaxResults(1).uniqueResult(); System.out.println(stu); tx.commit(); } catch (HibernateException he) { // TODO: handle exception if (tx != null) { tx.rollback(); } he.printStackTrace(); } finally { HibernateUtils.closeSession(session); } }
其实和上面的方法大同小异,没有什么大问题
3、投影查询:
/** * 投影查询 */ @Test public void selectProjection() { Transaction tx = null; Session session = null; try { session = HibernateUtils.getSession(); tx = session.beginTransaction(); String hql = "select stu.id, stu.name,stu.age from Student stu"; Query query = session.createQuery(hql); @SuppressWarnings("unchecked") List<Object[]> objList = query.list(); for (Object objs[] : objList) { for (Object obj : objs) { System.out.println(obj); } System.out.println("------学生信息------"); } tx.commit(); } catch (HibernateException he) { // TODO: handle exception if (tx != null) { tx.rollback(); } he.printStackTrace(); } finally { HibernateUtils.closeSession(session); } }
不难发现,这里的HQL语句和SQL语句很相似,只是要注意一点,查询得到的结果是一个Object类型的数组,这样就不爽了,不能转化成我们的Student的对象,为此,就有了下面的方法。
4、实例化的投影查询:
/** * 实例化的投影查询 */ @Test public void selectProjectionInstantiated() { Transaction tx = null; Session session = null; try { session = HibernateUtils.getSession(); tx = session.beginTransaction(); String hql = "select new Student(stu.name,stu.age) from Student stu"; Query query = session.createQuery(hql); @SuppressWarnings("unchecked") List<Student> list = (List<Student>) query.list(); for (Student stu : list) { System.out.println(stu); } tx.commit(); } catch (HibernateException he) { // TODO: handle exception if (tx != null) { tx.rollback(); } he.printStackTrace(); } finally { HibernateUtils.closeSession(session); } }
为了实现功能,我们需要为Student类添加一个包含两个参数(name和age)的构造方法:
/** * 构造方法 * @param name * @param age */ public Student(String name,int age){ this.name=name; this.age=age; }
5、where条件查询:
/** * 条件查询 */ @Test public void selectByCondition() { Transaction tx = null; Session session = null; try { session = HibernateUtils.getSession(); tx = session.beginTransaction(); String hql = "select stu from Student stu where stu.name='zhangsan'"; Query query = session.createQuery(hql); @SuppressWarnings("unchecked") List<Student> list = (List<Student>) query.list(); for (Student stu : list) { System.out.println(stu); } tx.commit(); } catch (HibernateException he) { // TODO: handle exception if (tx != null) { tx.rollback(); } he.printStackTrace(); } finally { HibernateUtils.closeSession(session); } }
这和SQL语句真的就很相同了,你想怎么写就怎么写吧,where查询条件有很多,就简单列举一点吧:
在where子句中可以指定 .号 比较运算符: =、>、>=、<、<=、<> 、is null 、is not null 范围运算符: in (值1, 值2 …) : 等于列表中的某一个值 not in(值1, 值2 …) : 不等于列表中的任意一个值 between 值1 and 值2 : 在值1到值2的范围内(包括值1和值2) not between 值1 and 值2 : 不在值1到值2的范围内 字符串模式匹配: like '字符串模式' 字符串模式中可用“%”代表任意长度的字符串,“_”代表任意单个字符。 逻辑运算: and (与)、 or (或)、not (非) 用于集合的运算符:is empty、is not empty
6、HQL函数查询:
/** * HQL函数查询 */ @Test public void selectByHQLFunc() { Transaction tx = null; Session session = null; try { session = HibernateUtils.getSession(); tx = session.beginTransaction(); String hql = "select new Student(upper(stu.name),lower(stu.clazz)) from Student stu "; Query query = session.createQuery(hql); @SuppressWarnings("unchecked") List<Student> list = (List<Student>) query.list(); for (Student stu : list) { System.out.println(stu); } tx.commit(); } catch (HibernateException he) { // TODO: handle exception if (tx != null) { tx.rollback(); } he.printStackTrace(); } finally { HibernateUtils.closeSession(session); } }
这只是简单的一个例子,hibernate为我们提供了很多强大而方便的函数,简单地列举一点吧:
1.字符串相关 upper(s) 、lower(s) 、 concat(s1, s2) 、substring(s,offset,length) 、 length(s)、 trim([[both|leading|trailing] char [from]] s)、locate(search, s, offset) 2.数字 abs(n) 、sqrt(n)、mod(dividend, divisor) 3.集合 size(c) 返回集合中元素的个数 4.日期时间 current_date()、current_time()、current_timestamp() 返回数据库系统的日期、时间、时间戳 year(d)、month(d)、day(d)、hour(d)、minute(d)、second(d) 从指定的参数中提取相应的值、
7、动态参数绑定查询:
/** * 按照参数位置动态绑定查询 */ @Test public void selectByParamLocation() { Transaction tx = null; Session session = null; try { session = HibernateUtils.getSession(); tx = session.beginTransaction(); String hql = "select stu from Student stu where stu.name=? and stu.age=?"; Query query = session.createQuery(hql); query.setInteger(1, 22); query.setString(0, "wangwu"); @SuppressWarnings("unchecked") List<Student> list = (List<Student>) query.list(); for (Student stu : list) { System.out.println(stu); } tx.commit(); } catch (HibernateException he) { // TODO: handle exception if (tx != null) { tx.rollback(); } he.printStackTrace(); } finally { HibernateUtils.closeSession(session); } }
有没有发现,这和jdbc的查询方式很相似,我们知道hibernate对jdbc底层API进行了封装,这就体现出来了,除此外,还可以按照参数的名称进行查询,将上面的代码做如下修改:
String hql = "select stu from Student stu where stu.name=:name and stu.age=:age"; Query query = session.createQuery(hql); query.setInteger("age", 22); query.setString("name", "wangwu");
效果完全一样。
8、HQL去掉重复记录:
/** * HQL去掉重复记录 */ @Test public void selectDistinct() { Transaction tx = null; Session session = null; try { session = HibernateUtils.getSession(); tx = session.beginTransaction(); String hql = "select distinct stu.age,stu.name from Student stu"; Query query = session.createQuery(hql); @SuppressWarnings("unchecked") List<Object[]> list = query.list(); for (Object objs[] : list) { System.out.println(objs[0]); System.out.println(objs[1]); System.out.println("-----学生信息-----"); } tx.commit(); } catch (HibernateException he) { if (tx != null) { tx.rollback(); } he.printStackTrace(); } finally { HibernateUtils.closeSession(session); } }
这里要注意了,这里的去重是指多条完全一样的记录,可以看看我们数据库表中现在已存在的数据:
有两条一模一样的数据,运行上面的方法,看看结果:
可以发现只有4条记录被查询出来。除此之外,我们还可以发现这个方法查询的结果也是一个Object型的数组。或者说,只要不是查询的实体类的所有属性并且不通过实体类的对应的构造方法进行转化的HQL查询得到的结果都是Object型的数组。