Hibernate的优缺点
优点:
- 简化了JDBC繁琐的编码
- 对面向对象特性支持良好
- 可移植性好
缺点:
- 不适合需要使用数据库的特定优化机制的情况
- 不适合大规模的批量数据处理
配置文件的小技巧:
可以点开配置文件的可视化窗口,进行鼠标的点击选择 生成一些配置. - 持久化类应符合 JavaBean规范,建议使用包装类型
对象-关系映射文件
- 类-表
- 属性-字段
- 主键生成方式
根据主键列获取数据的方法:
Object get(Class c,serializable id) ; 获取没有的数据时 返回 NULL
Object load(Class c,serializable id) ; 获取没有的数据时 抛异常ObjectNotFoundException
Hibernate中java对象的三种状态
脏检查及缓存机制
脏检查
在Hibernate中,数据前后发生变化的对象,成为脏对象.
当对象被加入Session缓存中时,Session会给这个对象的值类型的属性复制一份快照.当这个对象的值发生改变时,这个对象就是脏对象, Hibernate会对Session中持久状态的对象进行检测,即比较这个对象的当前属性与它的快照进行对比检查,这种判断成为脏检查.
刷新缓存机制
当Session缓存对象中的属性发生变化时,Session并不会立即执行脏检查和执行相关的SQL语句,而是在特定的时间点,即刷新缓存时才执行. 提高了应用程序访问数据库的访问性能.
Session会在以下时间点刷新缓存:
- 应用程序显示调用Session的 flush() 方法时.
- 应用程序调用 Transaction 的 commit() 方法时.
HQL部分
HQL是完全面向对象的,它可以理解继承、多态和关联之类的概念.
HQL是面向对象的查询语言,其中没有表和字段的概念,只有类、对象和属性的概念,所以我们查询的就是类 ,条件就是属性.这里要注意下!!!
编写HQL语句
1.from子句
from cn.hibernate.entity.Dept //HQL语句中的查询所有语句不能 用 select(查询所有就直接 from)
from Dept //与上述的代码一致 省略了包名
from Dept dept //取别名 效果一致( 也可以用 As 指定 别名) 这里省略了As 关键字
2.select 子句
select子句用于选取对象和属性.
select dept.deptName from Dept as dept //获取部门的名称 (Dept类的 deptName属性)
3.where子句
where子句用于查询表达查询的限制条件
from Dept where deptName='SALES'
4.使用表达式
表达式一般用在 where子句中. 下面举两个例子
from Dept dept where lower(dept.deptName)='sales' //转化成小写进行条件对比
from Emp where year(hirDate)=1980 //获取1980年入职的员工 year()函数获取日期字段的年份
5.order by 子句
order by 子句用于按指定属性排序
from Emp order by hirDate asc //员工入职时间 升序 排序 (desc 降序)
执行HQL语句
步骤:
- 获取Session对象
- 编写HQL语句
- 创建Query对象
- 执行查询,得到查询结果
代码:
String hql="from Emp"; //定义HQL语句
Query query=currentSession().createQuery(hql);//构建Query对象
两种方式执行查询语句并获取查询结果
Query对象的 list() 方法 //返回类型 list接口
list()方法
只会执行一条查询语句,查询所有符合条件的记录.
Query对象的 iterate() 方法 //返回类型 iterator 迭代器 ( 注意: 与list()方法不同的是 需要在会话关闭之前测试查询结果)
iterate()方法
会首先查询出所有符合条件的主键值,然后在需要某一个对象的其他属性时,才生成按主键查询的SQL语句.即iterate()方法可能生成1+N条SQL语句.(有点延迟加载的意思)
在HQL语句中绑定参数
SQL字符串拼接不出现SQL注入等安全问题,我们使用参数绑定的方式.
1.按参数位置绑定
使用 **"?"**占位符来定义参数的位置,代码如下:
Query query=currentSession().createQuery(" from Emp where job=? and sal>?"); //使用占位符?来实现参数绑定
query.setString(0,job); //注意的是第一个参数的下标 是 0
query.setDouble(1,sal); //可使用setParameter()代替 无需类型的指定
2.按参数名称绑定
在HQL语句中可以定义命名参数,命名参数以 " : " 开头,代码如下:
Query query=currentSession().createQuery(" from Emp where :empJob=? and sal>:empSal ");
query.setString("empJob",empJob);
query.setDouble("empSal",empSal); //可使用setProperties()代替
除了以上的用于绑定参数的方法,Hibernate还提供了 setParameter() 方法,用来绑定任意类型的参数,当不便指定参数的具体类型时,可以使用 setParameter() 为参数赋值.代码如下:
1. setParameter() 不推荐
public List<Emp> getEmpListByJobAndSal(Object[]params){
String hql="from Emp where job=? and sal>?";
Query query = currentSession().createQuery(hql);
for (int i = 0; i < params.length; i++) {
query.setParameter(i, params[i]); //此方式对比上面的 ? 占位符省去了复杂的类型指定
}
return query.list();
}
2.setProperties() 推荐(符合Hibernate面向对象宗旨)
setProperties(): 绑定命名参数与一个对象的属性值
3.uniqueResult() 获取唯一结果
只有当查询结果不是唯一时,不能使用 query.uniqueResult() 方法,否则会出错.
分页和投影
在以前的项目中要实现分页功能,需要复杂的SQL语句来实现.Hibernate提供了简便的方法实现分页,即通过Query接口的 setFirstResult(int firstResult) 方法和 setMaxResults(int maxResults) 方法实现.
1.分页实现
setFirstResult(int firstResult) 方法,设置起始位置.
setMaxResults(int maxResults) 方法,设置最大返回结果数.
2.使用投影查询
有时数据展示并不需要获取对象的全部属性,而是只需要对象的某一个属性或某几个属性,或者需要通过表达式、聚合函数等方式得到某些结果,此时可以使用投影查询.投影查询需要使用HQL的select 子句.对于投影结果的封装,有以下三种常见情况.
封装成Object对象
// 投影 (1)每条查询结果仅包含一列
public List<Object> findAllNames() {
String hql = "select dname from Dept";
return currentSession().createQuery(hql).list();
}
封装成Object数组
// 投影 (2)每条查询结果包含不止一列
public List<Object[]> findDeptList() {
String hql = "select deptno,dname from Dept";
return currentSession().createQuery(hql).list();
}
通过构造方法封装成对象
得到的对象不是持久化状态,仅用于封装结果.
// 投影 (3)希望以对象的方式使用查询结果
public List<Dept> findAllDeptList() {
// 这种方式 要求Dept类中必须包含 Dept(Byte deptno, String dname) 和Demp()构造方法
String hql = "select new Dept(deptno,dname) from Dept";
return currentSession().createQuery(hql).list();
}