3.lazy:指定关联对象延迟加载策略,默认为true.
4.fetch:设置抓取数据的策略,默认为select.
5.inverse:描述对象之间关联关系的维护方式,默认为false.
在Student.hbm.
Student表的hibernate.hbm.
需要注意的是在Student.hbm.
<?
在配置Student对象和Course对象时候我们注意到有两个属性:cascade(级联)和inverse(反转)
1.cascade属性:级联操作是指当主控方执行某项操作时,是否要对被关联放也执行相同的操作,常用的有<many-to-one/>,<one-to-one/>,<set/>,使用cascade属性的常用值如下:
(1).all:对所有操作进行级联操作。
(2).save-update:执行保存和更新操作时进行级联操作。
(3).delete:执行删除操作时进行级联操作。
(4).none:对所有操作不进行级联操作。
2.inverse属性:是对象之间关联关系的维护方式,它可以将维护关联关系的任务反转,由对方完成,inverse只存在与集合标记的元素中,inverse为true时,数量为一的一方反转关联关系维护给多的一方,inverse为false时为主动方,有主动方负责维护关联关系。
二、Hibernate检索方式
Hibernate中提供了一下几种在数据库中检索对象的方式:
(1).导航对象图检索方式:根据已经加载的对象,导航到其他对象,如关联对象的查询。
(2).OID检索方式:按照对象的OID来检索对象。
(3).HQL检索方式:使用专门的HQL查询接口和面向对象的HQL查询语言。
(4).QBC(Query By Criteria)检索方式:QBC提供的API来检索对象,这种API封装了基于字符串形式的查询语言,提供了更加面向对象的查询接口。
(5).本地SQL检索方式:这也是官方推荐的标准查询方式。
2.1、HQL查询
HQL(Hibernate Query Language)是Hibernate提供的一种面向对象的查询语言,HQL提供了了更加丰富灵活并且强大的功能。
>使用HQL可以避免使用JDBC查询的一些弊端,不需要再编写复杂的sql,将针对实体类及属性进行查询。
>查询结果直接放在List中的对象中,不需要,再次封装。
>独立于数据库,对不同的数据库根据Hibernate dialect属性自动生成不同的sql语句。
Query接口是HQL查询接口,提供了各种查询功能,它相当于JDBC的Statement和PreparedStatement,通过Session的createQuery创建其对象。理解其list()与iterate()方法的查询机制,将有助于查询性能的优化。
>list()方法返回List对象,iterate()方法直接返回Iterator对象。
>list()方法将不会在缓存中读取数据,它总是一次性地从数据库中直接查询所有符合条件的数据,同时将获取的数据写入缓存。
>iterate()方法是获取符合条件的数据的id后,需要时根据id在缓存中寻找符合条件的数据,若缓存中没有符合条件的数据,再到数据库中查询。
HibernateUtil工具类:
package com.pb.hibernate.util;import org.hibernate.HibernateException;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;public class HibernateUtil { /** * 初始化一个ThreadLocal对象,ThreadLocal对象有get(),set()方法; */ private static final ThreadLocal<Session> sessionTL=new ThreadLocal<Session>(); private static Configuration conf; private static SessionFactory sf; //静态代码块,只执行一次 static{ try { //解析配置文件 conf=new Configuration().configure(); //创建sesssion工厂 sf=conf.buildSessionFactory(); } catch (Exception e) { e.printStackTrace(); } } /** * 得到session对象,同时设置session对象到ThreadLocal对象 * 确保一个线程用一个session对象,而不是多个线程共享一个session对象 * @return 从ThradLocal对象中得到的session对象 */ public static Session getCurrentSession(){ //多线程不公用session Session session=sessionTL.get(); if (session==null) { //得到session对象 session=sf.openSession(); //将session对象保存到threadLocal对象中 sessionTL.set(session); } return session; } /** * 关闭session ,同时从ThreadLocal对象中清除缓存 */ public static void closeSession(){ Session session =sessionTL.get(); sessionTL.set(null);//先清空threadLocal session.close(); } }
DAO层使用hql查询:
/** * 通过hql语句的query.list()方法得到所有的像的集合 * @return */ public List<Dept> getAll(){ //1.得到session Session session=HibernateUtil.getCurrentSession(); //2.hql语句 String hql="from Dept"; //得到query对象 Query query=session.createQuery(hql); List<Dept> list=query.list(); return list; }
2.2、属性查询
属性查询只查找持久化类的部分属性而不是全部属性,通过属性查询有两种方式:
(1).通过直接指定属性进行属性查询,例如:
/** * @param deptName * @param location * @return */ public List<Dept> getDeptByNameAndLoc(String deptName,String location){ Session session=HibernateUtil.getCurrentSession(); String hql="select deptName,location from Dept"; Query query=session.createQuery(hql); List<Object[]> list2=query.list(); for (Object[] objects : list2) { System.out.println(objects[0]+""+objects[1]); } return null; }
(2).通过构造方法进行属性查询,使用这种方法需要持久化类中添加相应的构造方法。
/** * @param deptName * @param location * @return */ public List<Dept> getDeptByNameAndLoc(String deptName,String location){ Session session=HibernateUtil.getCurrentSession(); String hql="select new Dept( deptName,location) from Dept"; Query query=session.createQuery(hql); List<Object[]> list2=query.list(); for (Object[] objects : list2) { System.out.println(objects[0]+""+objects[1]); } return null; }
2.3、参数绑定
(1).使用"?"占位符。
public List<Dept> getDeptByDeptName(String deptName){ Session session=HibernateUtil.getCurrentSession(); String hql="from Dept where deptName like ? "; Query query=session.createQuery(hql); //setXxx ;Xxx:数据类型 query.setString(0,"%"+deptName+"%"); List<Dept> list=query.list(); return list; }
(2).使用命名参数。
//参数名称绑定参数 public List<Dept> get(){ Session session=HibernateUtil.getCurrentSession(); //命名参数 String hql="from Dept where deptName=:deptName"; Query query=session.createQuery(hql); /** * 实体类以及对应的映射文件,自动生成 * 方向工程 */ query.setString("deptName", "deptName");
// query.setParameter("deptName","deptName"); List<Dept> list=query.list(); for (Dept dept : list) { System.out.println(dept.getDeptName()); } return null; }
2.4、Hibernate分页
/** * 通过hql语句的query.list()方法得到所有的像的集合 * 分页查询 * @return */ public List<Dept> getAll(int pageIndex){ //1.得到session Session session=HibernateUtil.getCurrentSession(); //2.hql语句 String hql="from Dept"; //得到query对象 Query query=session.createQuery(hql); /** * 每页显示2条数据 * 显示第五页 */ query.setMaxResults(3);//pageSize每页显示多少条数据 query.setFirstResult((pageIndex-1)*3);//设置第一个,不包括第一个数据(pageIndex-1)*pageSize List<Dept> list=query.list(); return list; } /** * 得到总页数 * @param deptName * @return */ public int getTotalCount(String deptName){ Session session=HibernateUtil.getCurrentSession(); StringBuffer hql=new StringBuffer("select count(*) from Dept where 1=1"); List params=new ArrayList(); if (deptName!=null&&!"".equals(deptName)) { hql.append(" and deptName like ?"); params.add("%"+deptName+"%"); } Query query=session.createQuery(hql.toString()); for (int i = 0; i < params.size(); i++) { query.setParameter(i, params.get(i));//第二个参数放入的是Object类型 } long count =(Long)query.uniqueResult(); int totalCount=(int)count; if (totalCount%3==0) { return totalCount/3; }else { return totalCount/3+1; } }
2.5、Criteria查询概述
Criteria查询(Query By Criteria, QBC)是与HQL完全不同的一种查询机制。Criteria查询又称对象查询,它采用对象的方式,封装查询条件,并提供了Restriction等类型做辅助,可以使编写查询代码更加方便。
使用Criteria的示例:
/** * 使用Criteria查询 */ public Dept getDeptByCriteria(){ try { Session session=HibernateUtil.getCurrentSession(); Criteria criteria = session.createCriteria(Dept.class); Dept dept=(Dept) criteria.uniqueResult(); return dept; } catch (HibernateException e) { e.printStackTrace(); } return null; } public Dept getDeptByCriteriaUseRestrictions(){ try { Session session=HibernateUtil.getCurrentSession(); Criteria criteria = session.createCriteria(Dept.class); criteria.add(Restrictions.eq("deptNo", "101"));// 添加限制条件 //criteria.addOrder(Order.desc("deptNo"));排序 Dept dept=(Dept) criteria.uniqueResult(); return dept; } catch (HibernateException e) { e.printStackTrace(); } return null; }
在Criteria查询中使用Example示例查询:
在使用Criteria查询时,设定查询条件并非一定使用Restrictions,如果属性条件更多,使用Restrictions也不方便,Criteria允许先创建一个对象模板,以这样一个对象模板作为查询依据,查询出来属性与类似的对象。也就是依照已有的对象,查询与其属性相同或者相似的其他对象,这种查询也称示例查询(Query By Example,QBE)。
public List<Dept> getDeptByExample(){ List<Dept> result = null; try { Session session=HibernateUtil.getCurrentSession(); Dept dept = new Dept(); dept.setLocation("上海"); Criteria criteria = session.createCriteria(Dept.class); /** * Hibernate在自动生成SQL语句时,将自动过滤对象的空属性, * 根据有非空属性生成查询条件,如果要想更加精准可以设置更多属性值 */ criteria.add(Example.create(dept)); result = criteria.list(); return result; } catch (HibernateException e) { e.printStackTrace(); } return null; }
使用Criteria实现统计、分组、分页:
/** * 使用Criteria查询 */ public List<Dept> getDeptByCriteria(){ List<Dept> result = null; try { Session session=HibernateUtil.getCurrentSession(); Criteria criteria = session.createCriteria(Dept.class); criteria.setProjection(Projections.projectionList() .add(Projections.groupProperty("deptName")) // 按部门名称分组 .add(Projections.rowCount()) // 统计所有记录数 .add(Projections.avg("deptName"))// 统计平均数 .add(Projections.max("deptNo")));// 求最大 result= criteria.list(); return result; } catch (HibernateException e) { e.printStackTrace(); } return null; } //分页 public List<Dept> getDeptByCriteriaPage(){ List<Dept> result = null; try { Session session=HibernateUtil.getCurrentSession(); Criteria criteria = session.createCriteria(Dept.class); criteria.setFirstResult(1); criteria.setMaxResults(3); result= criteria.list(); return result; } catch (HibernateException e) { e.printStackTrace(); } return null; }
2.6、命名HQL查询
在Dept.hbm.
<?
查询:
public List<Dept> getDeptByCriteria(){ List<Dept> result = null; try { Session session=HibernateUtil.getCurrentSession(); Query query = session.getNamedQuery("dept"); Dept dept = new Dept(); dept.setDeptNo(101); query.setProperties(dept); result= query.list(); return result; } catch (HibernateException e) { e.printStackTrace(); } return null; }
2.7、DetachedCriteria查询
public List<StudentExam> getAllExamByExamId(Integer examId, String[] classIds) { DetachedCriteria detachedCriteria = DetachedCriteria .forClass(getEntityClass()); detachedCriteria.add(Restrictions.eq("exam.id", examId)); detachedCriteria.add(Restrictions.eq("isDelete", MySchoolConstant.IS_DELETED_NO)); boolean error = false; Integer[] intClassIds = new Integer[classIds.length]; for (int i = 0; i < classIds.length; i++) { if (StringUtils.isEmpty(classIds[i])) { error = true; break; } intClassIds[i] = Integer.valueOf(classIds[i]); } if (!error && intClassIds.length > 0) { detachedCriteria.add(Restrictions.in("classId", intClassIds)); } return findList(detachedCriteria); }
2.8、本地sql查询
HQL查询并不能涵盖所有的查询特性,一些复杂的查询还必须借助sql达到期望的目标,也就是本地sql,使用query.createSQLQuery(String sql)方法,同时使用addEntity()方法将别名与实体类关联起来。
public ZAnswer findStudentZAnswerListByParams(Integer recruitId,Integer examId,Integer questionId,Integer userId) { StringBuffer sql = new StringBuffer(); sql.append(" SELECT * FROM Z_ANSWER t "); sql.append(" WHERE t.`IS_DELETED` = 0 "); sql.append(" AND t.`RECRUIT_ID` = :recruitId "); sql.append(" AND t.`EXAM_ID` = :examId "); sql.append(" AND t.`TEST_QUESTION_ID` = :questionId "); sql.append(" AND t.`ANSWER_USER_ID` = :userId "); sql.append(" ORDER BY t.`IS_CURRENT` DESC,t.`CREATE_TIME` DESC "); Query query = this.getSession().createSQLQuery(sql.toString()).addEntity(ZAnswer.class); query.setParameter("recruitId", recruitId); query.setParameter("examId", examId); query.setParameter("questionId", questionId); query.setParameter("userId", userId); @SuppressWarnings("unchecked") List<ZAnswer> result = query.list(); //取得第一条记录 ZAnswer answer = null; //排除重复 if(result.size() > 0){ answer = (ZAnswer) result.get(0); for (ZAnswer zAnswer : result) { if(zAnswer.getId() != answer.getId()){ zAnswer.setIsDelete(1); this.update(zAnswer); } } } return answer; }
2.9、Hibernate调用存储过程
创建两个存储过程,在存储过程中in表示输入,out表示输出。
1.根据id查找某条数据:
CREATE PROCEDURE `findEmpById`(IN id INTEGER(11)) begin select * from emp where empId=id;end;
2.根据id查找某个字段并返回
CREATE PROCEDURE `getNameById`(in id integer(11),out eName varchar(50)) begin select empName into eName from emp where empId=id; end;
调用第一个存储过程:
package com.test;import java.sql.CallableStatement;import java.sql.Connection;import java.sql.ResultSet;import java.sql.SQLException;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;public class 调用存储过程 { /** * @param args * @throws SQLException */ public static void main(String[] args) throws SQLException { Configuration cfg = new Configuration().configure(); SessionFactory factory = cfg.buildSessionFactory(); Session session = factory.openSession(); Connection con = session.connection(); String sql = "{call findEmpById(?)}"; CallableStatement cs = con.prepareCall(sql); cs.setObject(1, 2); ResultSet rs = cs.executeQuery(); while(rs.next()){ int id = rs.getInt("empId"); String name = rs.getString("empName"); System.out.println(id+"\t"+name); } }}
调用第二个存储过程:
package com.test;import java.sql.CallableStatement;import java.sql.Connection;import java.sql.SQLException;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;public class 调用存储过程1 { public static void main(String[] args) throws SQLException { Configuration config = new Configuration().configure(); SessionFactory sessionFactory = config.buildSessionFactory(); Session session = sessionFactory.openSession(); Connection conn = session.connection(); String sql = "{call getNameById(?,?)}"; CallableStatement cs = conn.prepareCall(sql); cs.setObject(1, 3); //设置输出参数 cs.registerOutParameter(2, java.sql.Types.VARCHAR); //设置第二个参数为输出参数 cs.execute(); //调用存储过程 String name = cs.getString(2);//获取输出参数 System.out.println(name); }}
原标题:Hibernate关联映射及高级查询
关键词:Hibernate