Hibernate 第 6 天
知识框架 | |
1 hql(二) | 1) list和iterate方法的区别(面试的重点) |
当查询对象 | |
当查询属性的时候 | |
2) count(*)返回的结果必须使用long来保存 | |
2 hibernate中的一级缓存 | 1) 缓存的基本概念: |
2) 一级缓存的内部结构: | |
3) 一级缓存的生命周期,跟session保存一致 | |
4) get , load ,iterate 支持一级缓存的读写 list , save 可以写入一级缓存,但不能读 | |
5) 一级缓存的管理 | |
6) 一级缓存注意 | |
3 hibernate中的二级缓存 | 1) 二级缓存的定义 |
2) 二级缓存的生命周期 | |
3) 二级缓存内部结构Hashtable | |
4) 使用二级缓存的步骤 | |
5) ehcache.xml | |
6) 在hibernate.cfg.xml指定把那个对象放入二级缓中 | |
7) load , get, iterate支持二级缓存的读写 list只能写入二级缓存,不能读取二级缓存 | |
8) 管理二级缓存 |
1 hql(二)
1) list和iterate方法的区别(面试的重点)
查询所有的person对象
当查询对象
List (): 只发出了一条sql语句,直接查询所有的对象
iterate(): 首先查询对象的Id(“1”)的sql,然后根据id发出n条sql查询对象(“n”),n+1问题
当查询属性的时候
list()和 iterate():都只发出了一条查询属性的sql语句
2) count(*)返回的结果必须使用long来保存
案例:hibernate_day06_hql12
package com.tarena.test;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.junit.Test;
import com.tarena.po.Person;
import com.tarena.util.HibernateUtils;
public class HqlTest {
@Test
public void testSave(){
Session session = null;
try {
session = HibernateUtils.getSession();
for(int i=1; i<=6 ;i++){
session.beginTransaction();
Person person = new Person();
person.setAge(i+10);
person.setPname("IamNO"+i);
person.setBirthday(new Date());
person.setSalary(i*10000);
session.saveOrUpdate(person);
session.getTransaction().commit();
}
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally{
HibernateUtils.closeSession();
}
}
//查询所有的person对象
//当查询对象
// List (): 只发出了一条sql语句,直接查询所有的对象
//iterate(): 首先查询对象的Id(“1”)的sql,然后根据id
//发出n条sql查询对象(“n”),n+1问题
@Test
public void testQueryIteratorObject(){
Session session = HibernateUtils.getSession();
try {
// Iterator<Person> iterator
// =session.createQuery("from Person").iterate();
// 发出N+1条sql语句
//1 :iterate()首先去数据库中,查询对象的Id
//Hibernate: select person0_.id as col_0_0_ from
//t_person person0_
//N:iterate() 然后根据“1”中查询的id,去数据库发出
//N条sql语句,根据id查询所要的对象
//N:查询id的个数
// Hibernate: select person0_.id as id0_0_,
// person0_.t_pname as t2_0_0_, person0_.age as age0_0_, person0_.salary as salary0_0_, person0_.birthday as birthday0_0_ from t_person person0_
// where person0_.id=?
// IamNO1 ,11
List<Person> list =
session.createQuery("from Person")
.list();
Iterator<Person> iterator = list.iterator();
while(iterator.hasNext()){
Person person = iterator.next();
System.out.println(person.getPname()+" ,"+person.getAge());
}
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
}
//查询所有的person的age属性
//对比list与iterate在查询属性的时候,sql有什么不同
//iterate(): 只发出了一条sql语句,直接查询属性
//list():只发出了一条sql语句,直接查询属性
//查询属性的时候,list与iterate发出一样的sql
@Test
public void testQueryIterateList2(){
Session session = null;
try {
session = HibernateUtils.getSession();
//只发出一条查询属性的SQL语句
// Iterator<Integer> iterator =
// session.createQuery("select age from Person")
// .iterate();
//只发出一条查询属性的SQL语句
List<Integer> list =
session.createQuery("select age from Person")
.list();
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext()){
int age = iterator.next();
System.out.println(age);
}
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
}
//2 统计查询
//查询t_person表中有多少条数据
@Test
public void testCount(){
Session session = null;
try {
session = HibernateUtils.getSession();
long count =(Long) session.createQuery(
"select count(*) from Person")
.list().get(0);
System.out.println(count);
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
}
}
2 hibernate中的一级缓存
1) 缓存的基本概念:
缓存:是数据库中数据临时的保存到内存中一块区(数据库中的数据在内存中的临时拷贝),位于数据库和访问层之间。
作用:提高性能,减少对数据库的访问
缓存的使用方式:ORM在进行数据的读取的时候,会根据hibernate中的缓存策略,首先去缓存查询所要查询的数据
如果发现,直接使用,如果没有,发出sql语句,去数据库中查询,避免对数据库无谓的访问
针对对象:hibernate把缓存分成两个层次,一级缓存和二级缓存
一级缓存:为当前这个用户来缓存数据(私有)
二级缓存:跟SessionFactory有关,公有的
2)一级缓存的内部结构: 一级缓存的内部结构,就是一个Map<Key,Value>, Map中的key,指的当前的Id,Value
指对应的实体对象,因为是map结构,一级缓存只能保存实体对象,不能保存属性
3)一级缓存的生命周期,跟session保存一致,一级缓存也叫session级缓存,当session关闭的时候,一级缓存清空
4) get , load ,iterate 支持一级缓存的读写
list , save 可以写入一级缓存,但不能读
5) 一级缓存的管理(是否清空一级缓存):
批量插入,必须要时刻管理一级缓存 ,在企业开发中一旦出现批处理的问题,都不会使用hibernate,而是直接使用jdbc
hibernate当中使用jdbc:session.connection()
清理缓存:
session.flush();
session.clear();
6) 一级缓存注意:
a)一定要注意关闭session,不然很容易出现内存泄露
b) 一级缓存不能关闭,是hibernate默认就使用的,要时刻注意一级缓存的管理
案例:hibernate_day06_Cache1
package com.tarena.test;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.junit.Test;
import com.tarena.po.Person;
import com.tarena.util.HibernateUtils;
public class CacheTest {
@Test
public void testSave(){
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Person person = new Person();
person.setAge(23);
person.setBirthday(new Date());
person.setPname("li");
person.setSalary(12000);
session.saveOrUpdate(person);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally{
HibernateUtils.closeSession();
}
}
//一级缓存:是默认打开的
//在同一个session中,使用load方法连续查询同一个对象
//load方法可以读写一级缓存
//读: 能从一级缓存中读取数据
//写:能把数据写入到一级缓存中
@Test
public void testCacheLoad1(){
Session session = null;
try {
session = HibernateUtils.getSession();
Person person = (Person) session.load(Person.class, 1);
System.out.println(person.getAge()+","+person.getPname());
System.out.println("------------------------------");
//没有发出sql,因为上次调用load 方法的时候,就该
//写入一级缓存中,当第2次再查询同一个对象的时候
//hibernate首先会去一级缓存中,查询该对象,有,
//则直接使用
Person person2 = (Person) session.load(Person.class, 1);
System.out.println(person2.getAge()+","+person2.getPname());
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
}
//在一个session内部两次调用get查询同一个对象
// get依然支持一级缓存,可以读写一级缓存
@Test
public void testCacheGet1(){
Session session = null;
try {
session = HibernateUtils.getSession();
Person person = (Person) session.get(Person.class, 1);
System.out.println(person.getPname());
System.out.println("---------------------------------");
Person person2 = (Person) session.get(Person.class, 1);
System.out.println(person2.getPname());
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
}
//在两个session中调用分别调用load查询同一个对象
//Session 关闭,则一级缓存清空,一级缓存的生命
//周期跟session一致,一级缓存也叫session级缓存
@Test
public void testCacheLoad2(){
Session session = null;
try {
session = HibernateUtils.getSession();
Person person = (Person) session.load(Person.class, 1);
System.out.println(person.getPname());
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
System.out.println("---------------------------------");
try {
session = HibernateUtils.getSession();
Person person = (Person) session.load(Person.class, 1);
//发出sql语句,上次查询的时候,是person对象放入
//一级缓存当中,但随着session的关闭,一级缓存
//清空,而内部保存的person对象也随之消失
//当再次查询同一个Person对象的时候,缓存没有
//与之对应对象,只能发出sql语句,去数据库中
//查询
System.out.println(person.getPname());
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
}
//在一个session中调用两次Iterate方法查询同一个
//对象
//iterate()读写一级缓存
@Test
public void testQueryIterate1(){
Session session = null;
try {
session = HibernateUtils.getSession();
Iterator<Person> iterator =
session.createQuery("from Person").iterate();
while(iterator.hasNext()){
Person person = iterator.next();
System.out.println(person.getPname());
}
System.out.println("---------------------------------");
//只发出一条查询id的sql,iterate读写一级缓存,
//上次使用iterate查询出来的对象保存到一级缓存中
//但是一级缓存保存的是对象,id没有保存
//当第2次再使用iterate查询对象的时候,hibernate
//首先会先发出查询id的sql语句,然后根据id,去
//一级缓存中查询,看是否有与之匹配的对象,有
//直接使用
Iterator<Person> iterator2 =
session.createQuery("from Person").iterate();
while(iterator2.hasNext()){
Person person = iterator2.next();
System.out.println(person.getPname());
}
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
}
//在一个session中两次调用iterate来查询同一个person
//对象同的age属性
//一级缓存只能保存对象,不能保存属性
@Test
public void testCacheIterate(){
Session session = null;
try {
session = HibernateUtils.getSession();
Iterator<Integer> iterator =
session.createQuery("select age from Person")
.iterate();
while(iterator.hasNext()){
int age = iterator.next();
System.out.println(age);
}
System.out.println("-------------------");
Iterator<Integer> iterator2 =
session.createQuery("select age from Person")
.iterate();
while(iterator2.hasNext()){
int age = iterator2.next();
System.out.println(age);
}
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
}
//在一个session中调用两次list方法来查询同样的对象
@Test
public void testList1(){
Session session = null;
try {
session = HibernateUtils.getSession();
List<Person> list =
session.createQuery("from Person").list();
Iterator<Person> iterator = list.iterator();
while(iterator.hasNext()){
Person person = iterator.next();
System.out.println(person.getPname());
}
System.out.println("---------------------------");
//发出sql,不能确定list是否读写一级缓存
List<Person> list2 =
session.createQuery("from Person").list();
Iterator<Person> iterator2 = list2.iterator();
while(iterator2.hasNext()){
Person person = iterator2.next();
System.out.println(person.getPname());
}
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
}
// list 可以写入一级缓存,不能读取一级缓存
// 能写不能读
//在一个session中,首先使用list先查询对象,然后再
//使用iterate查询同样的对象,确定list对一级缓存
//支持情况
@Test
public void testListIterate(){
Session session = null;
try {
session = HibernateUtils.getSession();
List<Person> list =
session.createQuery("from Person").list();
Iterator<Person> iterator = list.iterator();
while(iterator.hasNext()){
Person person = iterator.next();
System.out.println(person.getPname());
}
//只发出了一条查询id的sql语句,上次使用list查询
//对象的时候,list可以写入一级缓存,则把查询
//出来的对象放入了一级缓存当中,而iterate方法
//可以读写一级缓存,但先发出查询id的sql语句,
//然后根据id来查询缓存中的对象
System.out.println("-----------------------------");
Iterator<Person> iterator2 =
session.createQuery("from Person").iterate();
while(iterator2.hasNext()){
Person person = iterator2.next();
System.out.println(person.getPname());
}
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
}
//save可以写入一级缓存
// 在同一个session中,先使用save保存一个对象,
//调用get来查询该对象
@Test
public void testSaveGet(){
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Person person = new Person();
person.setAge(18);
person.setPname("wang");
session.save(person);
session.getTransaction().commit();
//没有发出sql语句,save把person在保存到数据库
//的同时,也把person对象放入一级缓存当中
System.out.println("-------------------------------");
Person person2 = (Person) session.get(Person.class, 3);
System.out.println(person2.getPname());
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
}
//一级缓存的管理:
//插入200条person对象,每隔20条,清理一下一级
//缓存
@Test
public void testManager(){
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
for(int i =1;i<=200;i++){
Person person = new Person();
person.setAge(i);
session.saveOrUpdate(person);
if(i%20==0){
System.out.println("清理缓存");
session.flush();
session.clear();
}
}
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally{
HibernateUtils.closeSession();
}
}
}
3 hibernate中的二级缓存
1) 二级缓存的定义:二级缓存也叫进程级缓存还叫SessionFactory级缓存,二级缓存可以让所有的session共享
2)二级缓存的生命周期:二级缓存的生命周期跟SessionFactory的生命周期一致,SessionFactory可以管理二级缓存
3)二级缓存内部结构Hashtable,二级缓存也是只能保存对象,不能保存属性,而且需要第3方的插件才可以使用二级缓存
4) 使用二级缓存的步骤:
a) 导入第3方jar:ehcache-1.2.3.jar
b) 修改hibernate.cfg.xml文件
(1)开启二级缓存
(2)声明二级缓存的提供商
<!-- 开启二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">
true</property>
<!-- 指明二级缓存的提供商 -->
<property name="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
c)提供二级缓存的配置文件:
src/ehcache.xml
5) ehcache.xml
maxElementsInMemory="10000"
// 二级缓存中能保存的对象的数量最大值
eternal="false"
// 二级缓存中保存的对象是否永远有效,
false : 不是永远都有效(企业开发一般配置false)
true: 永远有效
timeToIdleSeconds="120"
// 两次访问该对象的最大的间隔时间,超过此时间
// 该缓存中的对象消失
timeToLiveSeconds="120"
//缓存中的对象的最大生命周期为120秒,超过
//该时间,该对象消失
overflowToDisk="true"
//当二级缓存的对象太多了以后,可以临时
//把对象保存到硬盘当中
6)在hibernate.cfg.xml指定把那个对象放入二级缓存
中
<class-cache usage="read-only"
class="com.tarena.po.Person"/>
7) load , get, iterate支持二级缓存的读写
list只能写入二级缓存,不能读取二级缓存
8) 管理二级缓存
二级缓存需要使用SessionFactory来进行管理
evict(po类.class, id):根据id删除二级缓存中的对象
evict(po类.class):删除二级缓存中所有的po类的对象
案例:hibernate_day06_Cache2
package com.tarena.test;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.Test;
import com.tarena.po.Person;
import com.tarena.util.HibernateUtils;
public class Cache2Test {
@Test
public void testSave(){
Session session = null;
try {
session = HibernateUtils.getSession();
for(int i=1; i<=6 ;i++){
session.beginTransaction();
Person person = new Person();
person.setAge(i+10);
person.setPname("IamNO"+i);
person.setBirthday(new Date());
person.setSalary(i*10000);
session.saveOrUpdate(person);
session.getTransaction().commit();
}
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally{
HibernateUtils.closeSession();
}
}
//load方法可以读写二级缓存
//在两个session中,调用load查询同一个对象
@Test
public void testCache2Load1(){
Session session = null;
try {
session = HibernateUtils.getSession();
Person person = (Person) session.load(Person.class, 1);
System.out.println(person.getAge());
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
System.out.println("________________________");
try {
session = HibernateUtils.getSession();
Person person = (Person) session.load(Person.class, 1);
//没有发出sql语句,上次使用load查询person对象的时候
//把person对象放入一级缓存当中,又把person对象放入
//而且缓存当中,当session关闭的时候,一级缓存
//清空,person在一级缓存中不存在了,但二级缓存
//的生命周期跟session无关,二级缓存中依然保存
//person对象,当再次使用load查找同一个person对象
//首先去缓存查找,有则使用,没有,去数据库中查询
System.out.println(person.getAge());
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
}
//get方法支持读写二级缓存
// 在两个session中调用get方法查询同一个person对象
@Test
public void testCacheGet1(){
Session session = null;
try {
session = HibernateUtils.getSession();
Person person = (Person) session.get(Person.class, 1);
System.out.println(person.getAge());
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
System.out.println("-------------------------------------");
try {
session = HibernateUtils.getSession();
// 没有发出sql语句
Person person = (Person) session.get(Person.class, 1);
System.out.println(person.getAge());
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
}
//iterate支持二级缓存的读写
//在两个session中调用iterate查询一样的person对象
@Test
public void testCache2Iterate(){
Session session = null;
try {
session = HibernateUtils.getSession();
Iterator<Person> iterator =
session.createQuery("from Person")
.iterate();
while(iterator.hasNext()){
Person person = iterator.next();
System.out.println(person.getAge());
}
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
System.out.println("------------------------------");
try {
session = HibernateUtils.getSession();
Iterator<Person> iterator =
session.createQuery("from Person")
.iterate();
while(iterator.hasNext()){
Person person = iterator.next();
System.out.println(person.getAge());
}
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
}
// 在两个session使用iterate来查询属性
//二级缓存不支持对属性的保存
@Test
public void testCache2Iterate2(){
Session session = null;
try {
session = HibernateUtils.getSession();
Iterator<String> iterator =
session.createQuery("select pname from Person")
.iterate();
while(iterator.hasNext()){
String name = iterator.next();
System.out.println(name);
}
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
System.out.println("---------------------------");
//发出sql语句,二级缓存不保存属性
try {
session = HibernateUtils.getSession();
Iterator<String> iterator =
session.createQuery("select pname from Person")
.iterate();
while(iterator.hasNext()){
String name = iterator.next();
System.out.println(name);
}
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
}
//在两个session中两次使用list来查询同样的person对象
@Test
public void testCache2List1(){
Session session = null;
try {
session = HibernateUtils.getSession();
List<Person> list =
session.createQuery("from Person")
.list();
Iterator<Person> iterator = list.iterator();
while(iterator.hasNext()){
Person person = iterator.next();
System.out.println(person.getPname());
}
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
System.out.println("_____________________");
try {
session = HibernateUtils.getSession();
List<Person> list =
session.createQuery("from Person")
.list();
Iterator<Person> iterator = list.iterator();
while(iterator.hasNext()){
Person person = iterator.next();
System.out.println(person.getPname());
}
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
}
//在两个session中,先使用list查询person对象,然后
//在使用iterate查询同样的person对象
@Test
public void testListIterate(){
Session session = null;
try {
session = HibernateUtils.getSession();
List<Person> list =
session.createQuery("from Person")
.list();
Iterator<Person> iterator = list.iterator();
while(iterator.hasNext()){
Person person = iterator.next();
System.out.println(person.getPname());
}
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
System.out.println("---------------------------");
//发出查询id的sql语句,上次使用list查询的时候,
//把person对象放入二级缓存当中,当再使用
//iterate查询同样的对象的时候,hibernate会先
//发出查询id的sql语句,然后根据id去二级缓存中
//查询所要的person对象
try {
session = HibernateUtils.getSession();
Iterator<Person> iterator =
session.createQuery("from Person").iterate();
while(iterator.hasNext()){
Person person = iterator.next();
System.out.println(person.getPname());
}
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
}
// 管理二级缓存
// 在两个session中,第1个session,使用load方法
// 查询id = 1,id =2的person对象,
// 管理二级缓存
//第2个session中,也使用load方法查询id =1,id=2的
//person对象
@Test
public void testManage(){
Session session = null;
try {
session = HibernateUtils.getSession();
Person person1 = (Person) session.load(Person.class, 1);
System.out.println(person1.getPname());
Person person2 = (Person) session.load(Person.class, 2);
System.out.println(person2.getPname());
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
System.out.println("------------------------------------");
SessionFactory factory = HibernateUtils.getSessionFactroy();
//去掉二级缓存中id = 2的person对象
//evict(po类.class, id):根据id删除二级缓存中的对象
//factory.evict(Person.class, 2);
//去掉二级缓存中所有的person对象
factory.evict(Person.class);
try {
session = HibernateUtils.getSession();
Person person1 = (Person) session.load(Person.class, 1);
System.out.println(person1.getPname());
Person person2 = (Person) session.load(Person.class, 2);
System.out.println(person2.getPname());
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession();
}
}
}