Hibernate Part6

原作者:尚硅谷-佟刚


HQL


这里写图片描述

这里写图片描述


hibernate.cfg.xml(主要配置)

<!-- jdbc.fetch_size jdbc.batch_size 对MySQL无效,对ORACLE有效 -->
        <!-- 配置JDBC的Statement读取数据的时候每次从数据库中取出的记录条数 -->
        <property name="jdbc.fetch_size">100</property>

        <!-- 设定对数据库进行批量删除,批量更新,批量插入的时候的批次的大小 -->
        <property name="jdbc.batch_size">30</property>

        <!-- 启用二级缓存 -->
        <property name="cache.use_second_level_cache">true</property>

        <!-- 配置使用二级缓存的产品 -->                             
        <property name="cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>

        <!-- 启用查询缓存 -->
        <property name="cache.use_query_cache">true</property>


        <!-- 配置管理Session的方式 -->
        <property name="current_session_context_class">thread</property>

        <!-- 需要关联的hibernate映射文件.hbm.xml -->
        <mapping resource="com/atguigu/hibernate/entities/Department.hbm.xml"/>
        <mapping resource="com/atguigu/hibernate/entities/Employee.hbm.xml"/>
        <!--设置缓存-->
        <class-cache usage="read-write" class="com.atguigu.hibernate.entities.Employee"/>         
        <class-cache usage="read-write" class="com.atguigu.hibernate.entities.Department"/>
        <collection-cache usage="read-write" collection="com.atguigu.hibernate.entities.Department.emps"/>

ehcache.xml


<ehcache>
    <!-- 
                指定一个目录:当EHCache把数据写到硬盘上时,将把数据写到这个目录上.
     -->
    <diskStore path="d:\\tempDirectory"/>

    <!-- 
                设置缓存的默认数据过期策略
     -->
    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        />


    <!-- 
                设置具体的命名缓存的数据过期策略,每个命名缓存代表一个缓存区域
                缓存区域:一个具有名称的缓存块,可以给每一个缓存块设置不同的缓存策略
                如何没有设置任何的缓存区域,则所有被缓存的对象,都将使用默认的缓存策略.
       Hibernate在不同的缓存区域保存不同的类/集合.
                对于类而言:区域的名称是类名
                对于集合而言:区域的名称是类名加属性名
     -->

    <cache name="com.atguigu.hibernate.entities.Employee"
        maxElementsInMemory="1"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="true"
        />


    <cache name="com.atguigu.hibernate.entities.Department.emps"
        maxElementsInMemory="1000"
        eternal="true"
        timeToIdleSeconds="0"
        timeToLiveSeconds="0"
        overflowToDisk="false"
        /> 

</ehcache>

@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, "%B%")
         .setEntity(2, dept);

    //3.执行查询
    List<Employee> emps=query.list();
    System.out.println(emps.size());
}

@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 testPageQuery(){
String hql=”FROM Employee”;
Query query=session.createQuery(hql);

    int pageNo=10;
    int pageSize=5;

    List<Employee> emps=query.setFirstResult((pageNo-1)*pageSize)
                             .setMaxResults(pageSize)
                             .list();
    System.out.println(emps);

}
Hibernate: 
    select
        * 
    from
        ( select
            row_.*,
            rownum rownum_ 
        from
            ( select
                employee0_.ID as ID1_1_,
                employee0_.NAME as NAME2_1_,
                employee0_.SALARY as SALARY3_1_,
                employee0_.EMAIL as EMAIL4_1_,
                employee0_.DEPT_ID as DEPT_ID5_1_ 
            from
                GG_EMPLOYEE employee0_ ) row_ 
        where
            rownum <= ?
        ) 
    where
        rownum_ > ?

//命名查询
@Test
public void testNameQuery(){
Query query=session.getNamedQuery(“salaryEmps”);

    List<Employee> emps=query.setFloat("minSal", 5000)
                             .setFloat("maxSal", 10000)
                             .list();

    System.out.println(emps.size());


}

//投影查询
@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 testFieldQuery2(){
String hql=”SELECT new Employee(e.salary,e.email,e.dept) ”
+ “FROM Employee e ”
+ “WHERE e.dept=:dept”;

    Query query=session.createQuery(hql);

    Department dept=new Department();
    dept.setId(80);

    List<Employee> emps=query.setEntity("dept",dept).list();

    for(Employee emp:emps){
        System.out.println(emp.getId()+", "+emp.getSalary()+", "
                    +emp.getEmail()+", "+emp.getDept());
    }
}

//报表查询
@Test
public void testGroupBy(){
String hql=”SELECT MIN(e.salary), MAX(e.salary) ”
+ “FROM Employee e ”
+ “GROUP BY e.dept ”
+ “HAVING MIN(e.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 testLeftJoinFetch(){
String hql=”SELECT DISTINCT d FROM Department d LEFT JOIN FETCH d.emps”;
// String hql=”FROM Department d LEFT JOIN FETCH d.emps”;
Query query=session.createQuery(hql);

    List<Department> depts=query.list();

    //利用LinkedHashSet集合的不可重复的特性去重

// 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 testLeftJoin(){

    String hql="FROM Department d LEFT JOIN  d.emps";
    Query query=session.createQuery(hql);

    //查询结果返回的是一个ArrayList<E>  E:Object[]

// List 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.size());

    for(Object[] objs:result){
        System.out.println(Arrays.asList(objs));
    }

}

@Test
public void testLeftJoinFetch2(){

   String hql="SELECT e FROM Employee e INNER JOIN FETCH 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 testHQLUpdate(){
String hql=”DELETE FROM Department d WHERE d.id=:id”;

    session.createQuery(hql)
           .setInteger("id",280)
           .executeUpdate();

}

Native SQL


@Test
public void testNativeSQL(){
    String sql="INSERT INTO gg_department VALUES(?,?)";
    Query query=session.createSQLQuery(sql);
    query.setInteger(0,280)
         .setString(1, "ATGUIUG")
         .executeUpdate();

}

SecondLevelCache


@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());
}
Hibernate: 
    select
        employee0_.ID as ID1_1_0_,
        employee0_.NAME as NAME2_1_0_,
        employee0_.SALARY as SALARY3_1_0_,
        employee0_.EMAIL as EMAIL4_1_0_,
        employee0_.DEPT_ID as DEPT_ID5_1_0_ 
    from
        GG_EMPLOYEE employee0_ 
    where
        employee0_.ID=?
King
King

@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());



}
Hibernate: 
    select
        department0_.ID as ID1_0_0_,
        department0_.NAME as NAME2_0_0_ 
    from
        GG_DEPARTMENT department0_ 
    where
        department0_.ID=?
Sales
Hibernate: 
    select
        emps0_.DEPT_ID as DEPT_ID5_0_1_,
        emps0_.ID as ID1_1_1_,
        emps0_.ID as ID1_1_0_,
        emps0_.NAME as NAME2_1_0_,
        emps0_.SALARY as SALARY3_1_0_,
        emps0_.EMAIL as EMAIL4_1_0_,
        emps0_.DEPT_ID as DEPT_ID5_1_0_ 
    from
        GG_EMPLOYEE emps0_ 
    where
        emps0_.DEPT_ID=?
34
Sales
34

QueryCache(依赖于二级缓存)

@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);
// criteria.list().size();
//
// criteria.list().size();
}


Hibernate:
select
employee0_.ID as ID1_1_,
employee0_.NAME as NAME2_1_,
employee0_.SALARY as SALARY3_1_,
employee0_.EMAIL as EMAIL4_1_,
employee0_.DEPT_ID as DEPT_ID5_1_
from
GG_EMPLOYEE employee0_
107
107


TimeStampCache


@Test
public void testUpdateTimeStampCache(){
Query query=session.createQuery(“FROM Employee”);
query.setCacheable(true);

    List<Employee> emps=query.list();
    System.out.println(emps.size());

    Employee emp=(Employee) session.get(Employee.class, 100);
    emp.setSalary(888844);


    emps=query.list();
    System.out.println(emps.size());
}

时间戳缓存区域存放了对于查询结果相关的表进行插入, 更新或删除操作的时间戳. Hibernate 通过时间戳缓存区域来判断被缓存的查询结果是否过期, 其运行过程如下:
T1 时刻执行查询操作, 把查询结果存放在 QueryCache 区域, 记录该区域的时间戳为 T1
T2 时刻对查询结果相关的表进行更新操作, Hibernate 把 T2 时刻存放在 UpdateTimestampCache 区域.
T3 时刻执行查询结果前, 先比较 QueryCache 区域的时间戳和 UpdateTimestampCache 区域的时间戳, 若 T2 >T1, 那么就丢弃原先存放在 QueryCache 区域的查询结果, 重新到数据库中查询数据, 再把结果存放到 QueryCache 区域; 若 T2 < T1, 直接从 QueryCache 中获得查询结果


ManagerSession


@Test
public void testManagerSession(){

    //开启事务
    Session session=HibernateUtils.getInstance().getSession();
    System.out.println("--->"+session.hashCode());

    Transaction transaction=session.beginTransaction();

    DepartmentDao departmentDao=new DepartmentDao();
    Department dept=new Department();
    dept.setName("我一定会回来的");

    departmentDao.save(dept);
    departmentDao.save(dept);
    departmentDao.save(dept);
    departmentDao.save(dept);

    //若Session是由thread来管理的,则在提交或回滚事务时,已经关闭Session了.
    transaction.commit();
    System.out.println(session.isOpen());
}

通过JDBC原生API进行操作


@Test
public void testBatch(){
session.doWork(new Work() {
@Override
public void execute(Connection connection) throws SQLException {
//通过JDBC原生的API进行操作,效率最高,速度最快!

    }
   });  
}

QueryIterate


Query query=session.createQuery(“FROM Employee e WHERE e.dept.id=80”);
List emps=query.list();
System.out.println(emps.size());

    Iterator<Employee> empIt=query.iterate();
    while(empIt.hasNext()){
        System.out.println(empIt.next().getName());
    }
Hibernate: 
    select
        employee0_.ID as ID1_1_,
        employee0_.NAME as NAME2_1_,
        employee0_.SALARY as SALARY3_1_,
        employee0_.EMAIL as EMAIL4_1_,
        employee0_.DEPT_ID as DEPT_ID5_1_ 
    from
        GG_EMPLOYEE employee0_ 
    where
        employee0_.DEPT_ID=80
34
Hibernate: 
    select
        employee0_.ID as col_0_0_ 
    from
        GG_EMPLOYEE employee0_ 
    where
        employee0_.DEPT_ID=80

1.Hibernate中一级缓存与二级缓存的区别?
一级缓存
1).一级缓存只缓存整个对象,不能缓存对象属性;
2).一级缓存是Session级的缓存,不能跨多个Session对象来使用;
3).Session的load/get方法支持一级缓存的读和写;
4).Query的list接口只支持一级缓存的写入,不能从一级缓存中读出对象。list接口加载对象要发出SQL;
5).Query的iterate接口既支持一级缓存的写入,也能从一级缓存中读取对象(如果有的话)。每次用iterate接口查询对象,都要先发SQL加载查询对象的id列表。如果需要用到某个对象,则根据该对象的id从一级缓存中查询,有则直接加载,没有则发出SQL从数据库加载(这时会出现1+N问题)。
6. Session的save方法会将save的对象放入一级缓存中,因此如果要save大批对象,则应该要及时清空一级缓存,可以采用Session的clear()方法。
7.一级缓存是hibernate 默认使用的,无需配置即可使用。

二、 二级缓存
1. 二级缓存也是只能缓存整个对象,不能缓存对象属性,而且对load/get方法、list/iterate方法的在使用上跟一级缓存一样。
2.与一级缓存不同,二级缓存是SessionFactory级的缓存,它允许多个Session对象之间共用。
3.使用二级缓存前必须进行一些准备步骤(以EhCache为例):
(1)需要有EhCache的xml配置文件(设置EhCache的“缓存对象最大数目”、“对象是否不失效”、“对象允许的空闲时间”、“对象的生存时间”及“对象数目超额时是否缓存至磁盘”);
(2)在总配置文件hibernate.cfg.xml中启用二级缓存(默认开启,无需显示配置):
true
(3)指定二级缓存的供应商:
org.hibernate.cache.EhCacheProvider
(4)指定需要缓存的类及缓存方式(可在hibernate.cfg.xml或对应的类的.hbm.xml中配置):
在hibernate.cfg.xml中配置:

在Student.hbm.xml中配置(必须在配置id前完成):

(5)可以通过Session动态设置是否允许对二级缓存进行读和写,方法是:session.setCacheMode(CacheMode.GET)和session.setCacheMode(CacheMode.PUT)
(6)SessionFactory的evit()会将一个对象逐处二级缓存。
三、 查询缓存
查询缓存是专为Query的list方法设计的。对于iterate()方法,无论是查询对象属性还是对象本身,查询缓存用与不用都没有区别!
1.用查询缓存查询属性:
(1)查询缓存必须要在hibernate.cfg.xml中显示启用:
true
(2)在代码中如果要用到查询缓存(无论是写还是读缓存),都要进行开启操作,可通过Query的setCacheable(true)方法开启;
(3)查询缓存的生命周期与Session无关(可以跨Session查询),当查询关联的表发生改变,那么查询缓存的生命周期结束(delete、update、modify)
(4)开启查询缓存,并用Query查询对象的属性(可以是一个或多个)时,采用Query的list方法可以把得到的属性集合写入查询缓存中。如果查询缓存已经有了该对象的属性,那么就不会发出SQL而直接从查询缓存中取出来;
2.用查询缓存查询对象:
(5)如果开启查询缓存并通过list接口查询对象,在首次查询时会发出SQL从数据库中获取对象,同时将对象的id列表放入查询缓存中;如果再次用查询缓存查询对象,则会根据该对象的id发出SQL从数据库中加载对象(这时会发出N条SQL语句)
(6) 如果同时开启查询和二级缓存,那么(5)中就不会发出N条SQL语句了,而是直接从二级缓存中加载。(此时的list接口有了读二级缓存的能力了!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值