hibernate05:二级缓存、一级与二级的差别、主键生成策略

第一.概念

Shift+第一个+最后一个=全部选中jar包
1.数据库和tomcat服务器不在一台电脑上,一级缓存是保存在服务器的内存中,二级缓存保存在服务器的硬盘上(因此我们可以设置溢出时保存到哪个硬盘),二级缓存也是在tomcat服务器上的,因此减少了与数据库的交互次数(因为保存到服务器的话不用跟其他的电脑进行交互)。
2.hibernate的一级缓存是session级别的缓存。sessionFactory级别的缓存是二级缓存。
3.二级缓存要指定hibernate的二级缓存插件(插件是个现成的程序,需要我们指定用这个插件),需要开启
4.hibernate主配置文件中的设置都是给某个类进行赋值,是个sessionFactory类(session工厂)中的属性赋值。sessionFactory是个接口,实现类是sessionFactoryimpl
资源文件Properties 继承了hashtable,因此Properties 是个键值对。
来自JDK1.6说明文档:Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。

5.在properties文件中#表示注释
6,使用二级缓存的步骤:
  ---1.开启二级缓存
 ---2.指定缓存插件(功能是把内容写到磁盘中,当开启二级缓存之后就该想到我们将来要把内容存到哪里)
  --3.写配置文件说明二级缓存的大小,在src下配置缓存文件
  --4.指定需要缓存的对象和缓存策略
7.statics是对二级缓存进行统计,输出来的内容create(可瑞的)是该对象的属性。在主配置文件中配置。
他是查看二级缓存或查询缓存区域的内容,但是如果想查看二级缓存,需要在主配置文件中进行配置。查看二级缓存是SessionFactory类中的的方法Statistics ss=HibernateSessionFactory.getSessionFactory().getStatistics();
其实不难理解为什么是SessionFactory类中的方法,因为SessionFactory表示的是二级缓存。而session表示一级缓存。

8.适合放入二级缓存中的数据:1.不经常做修改的数据,2.安全性不高的数据。
9.先查询已经缓存,一级缓存中如果没有在查询二级缓存,如果二级缓存中也没有,就查询数据库。
10.session(一级)和sesionFactroy(二级)的线程安全问题
 session是线程不安全的:ThreadLocal是给每个来的线程都给他一个副本,用这种方式来解决多线程问题。sessionFactroy是线程安全的。
注意:在hibernate主配置文件中,二级缓存的配置要放到映射文件配置的前面

11.session和sessionFactory都有evict方法,该方法的参数是个对象或者类,表示让该对象与一级缓存或者二级缓存断开联系:sessionFactory.evict(Cat.class, catId); sessionFactory.evict(Cat.class);
/**
关于二级缓存:二级缓存就是给大家共享的,每个线程都能够使用,因此就出现了多线程并发的现象。
      第一步(1):在hibernate主配置文件中写:
              
  
   org.hibernate.cache.EhCacheProvider
  

    
  
     false
  

  
  true
     第一步(2):在映射文件中写二级缓存的并发策略。usage表示并发策略。
 
     第二步:指定二级缓存的插件(有好多种插件都能实现二级缓存,其实就是把某个xml文件放到src目录下(放在src下就会随着项目的启动而启动二级缓存)。现在要指定插件,在老师给的hibernate-3.2下的ect目录下)
     第三步:配置上面的插件(可以只配置缓存的大小)
----------------------------------
注意:现在我们只导入了hibernate的jar包,在配置好二级缓存之后运行的时候报错Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory。
这是找不到这个jar包(也就是说明二级缓存要使用这个jar包),因此我们可以找一个这样的jar包放到项目中,也可以直接把struts框架的jar包生成,因为struts2框架的jar包就有这个jar包
并发策略有好多种,看张老师的,可是我们常用的只有两种只读模式和读写模式,当我们设置读写模式的时候就不能设置事务的隔离级别了,因为这两个是互相矛盾的。
**/

11.主键生成策略:
increment(k瑞特门):自动增长因用于mysql,
identity自增用于mysql,server,db2,
sequence是oracle中的自增
native(内t我):根据数据库自动匹配(相当于综合各种数据库),由数据库底层自己决定。
assigned:程序员自己指定
uuid:是个算法

12.hql的多表关联(多表关联有三种,一种是hql的多表关联,一个createCriteria(也就是QBC查询),一个是本地sql查询)
inner默认是内连接,inner join。左是left join
   内左外右外连接查询:查询结果是个object类型的数组,因为这个查询结果中包含两个或者两个以上的表(类),因此不能是具体类型,只能是object类型。因为包含多个表,表中又有属性,因此每个表都是一个数组。
   迫切查询:返回值是个对象

13.createCriteria多表关联
  两个参数,第一个是类名,第二个是别名,单词是alias
  两个参数,第一个参数表示地址,第二个参数是数据类型(在Criteria里面的常量)

14,hibernate的源码在hibernate-3.2这个老师给的文件中的src中,如果找二级缓存的资源文件在这个文件夹中的ect中。

一级缓存session的声明周期是与数据库的一次交互过程,当我们把session放到action层的时候,它的声明周期是一次请求和响应的过程(可能多次与数据库交互)
而二级缓存是:不但在一级缓存的map结构中存放(),还在二级缓存中存放(在二级缓存存放的内容是共享的)。
一级缓存的作用域相当于是hibernate主配置文件中的map标签里,而二级缓存的作用域相当于是整个hibernate主配置文件。
------------------
书17章:三种检索(查询)方式
1.hql语句检索:session.createQuery(hql);
2.QBC检索:session.createCriteria(XXX.class)
3.本地SQL检索:session.createSQLQuery(sql)
 

第二:代码

1、hibernate主配置文件


          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">



 

 
  org.hibernate.dialect.Oracle9Dialect
 

 
  jdbc:oracle:thin:@localhost:1521:ORCL
 

 chu1
 1234
 
  oracle.jdbc.OracleDriver
 

 chu
 true
 true
 
 
  org.hibernate.cache.EhCacheProvider
 

 
 
  true
 

 
 true
 
 true

 

 

 

2.basedao公共类

package com.comm;

import java.io.Serializable;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

public class BaseDao
{
 public static SessionFactory sf;
 static
 {
  Configuration cfg=new Configuration().configure("/hibernate.cfg.xml");
  sf = cfg.buildSessionFactory();
  System.out.println(sf);
 }

 public Session getSession()
 {
  return sf.openSession();
 }
 
 public Serializable save(Object obj)
 { 
  Transaction  tr=null;
  Session session=null;
  Serializable ser=null;
  try
  {
   session = this.getSession();
   
   tr= session.beginTransaction();
   
   ser=session.save(obj);
   
   tr.commit();
   
   
  }
  catch(Exception ex)
  {
   ex.printStackTrace();
  }
  finally
  {
   session.close();
  }
  return ser;
  
 }
 
 public static void main(String[] args) {
  new BaseDao();
 }
}

 

3.dao层

package com.model.dao;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.stat.Statistics;

import com.comm.BaseDao;
import com.comm.HibernateSessionFactory;
import com.model.pojo.Student6;

public class StudentDao extends BaseDao{
 //一级缓存。此时不开启二级缓存。在主配置文件中设置成false
 public void search(){
  Session session=super.getSession();
  Student6 stu=(Student6) session.get(Student6.class, 168);
  System.out.println(stu.getSname()+"\t"+stu.getSsex()); 
  //session.evict(stu);//将当前对象与session断开
  //session.clear();//清空session
  session.close();//关闭session
  Session session2=super.getSession();
  System.out.println("session是打开的?"+session.isOpen());
  //System.out.println("当前session"+session.hashCode());
  System.out.println(stu.getSname()+"\t"+stu.getSsex());//无论什么操作,这里都会输出值,因为这里跟缓存无关,由于限制存在一个完整的stu对象,所以理所当然的能够输出他的属性值。
    
 }
 //自己的session关闭之后其他session来访问相同的内容(id相同的学生),由于第一个session把查询结果放在了二级缓存中了,因此第二个session查询相同的学生的时候不会访问数据库而是直接去二级缓存中取,因此控制台输出一条sql语句
 public void search2(){
  Session session=HibernateSessionFactory.getSession();
  Student6 stu=(Student6) session.get(Student6.class, 168);
  System.out.println(stu.getSname()+"\t"+stu.getSsex());
  //session.clear();//清空一级缓存
  session.close();
  Session session2=HibernateSessionFactory.getSession();
  Student6 stu2=(Student6) session2.get(Student6.class, 168);//会查看二级缓存中有没有,当我们开启二级缓存的时候,使用二级缓存,因此不会再输出select语句了
  System.out.println(stu2.getSname()+"\t"+stu2.getSsex());//
  Statistics ss=HibernateSessionFactory.getSessionFactory().getStatistics();//getSessionFactory()是获得sesionFactory也就是获得二级缓存,getStatistics是获得二级缓存中的统计信息
  System.out.println(ss);
 }
 
 
 public static void main(String[] args) {
  StudentDao sdao = new StudentDao();
  //sdao.search();
  sdao.search2();
  //sdao.search3();
 }

}

 

 

第三:多表连接查询,对象查询的代码

1.员工表的映射文件


"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">


   
       
           
           
       

       
           
       

       
           
       

       
           
       

     
   

 

2.部门表的映射文件


"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">


   
       
           
           
       

       
           
       

       
           
               
           

           
       

   

3.连接查询和本地查询

package com.model.dao;

import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.hibernate.Query;
import org.hibernate.Session;

import com.comm.HibernateSessionFactory;
import com.model.pojo.Dept;
import com.model.pojo.Emp;

public class DeptDao {

 public static void main(String[] args) {
  DeptDao ddao=new DeptDao();
  //ddao.selDept();
  //ddao.selDept1();
  //ddao.selDept2();
  ddao.selDept3();
 }
 //通过这个方法我们发现内连接,左连接、右连接的查询结果是个object类型的数组
 public void selDept(){
  Session session=HibernateSessionFactory.getSession();
  String hql="from Dept as d inner join d.emps";
  Query query = session.createQuery(hql);
  List list = query.list();
  for(int x=0;x   System.out.print(list.get(x)+"    ");//这个得到的是个数组,也就是说集合里面放的是数组。由此得出结论
   System.out.println();
  }
  
 }
 //通过这个方法我们知道,数组中的每个元素都表示多表关联中的每个表,也就是说有几个表数组中就会有几个元素
 public void selDept1(){
  Session session=HibernateSessionFactory.getSession();
  String hql="from Dept as d inner join d.emps";
  Query query = session.createQuery(hql);
  List list = query.list();//首先查询结果有很多,是个list集合(query.list的返回值就是个list)。每个查询结果又是个数组,数组中的每个元素表示一个表(由于内连接,左右连接都是两个或者两个以上的表在参与)
  for(Object[] d:list){
   System.out.println(d[0].getClass().getName()+"\t"+d[1].getClass().getName());
  }  
 }
 //迫切左外连接。集合的返回值得到的是对象类型的list集合
 public void selDept2(){
  Session session=HibernateSessionFactory.getSession();
  String hql="from Dept as d left join  fetch d.emps";
  Query query = session.createQuery(hql);
  List list=query.list();
  for(Dept d:list){
   System.out.println(d.getDname());
   Set set=d.getEmps();
   Iterator it = set.iterator();
   while(it.hasNext()){
    System.out.println(it.next().getEname());
   }
  }
  
 }
 //本地sql查询
 public void selDept3(){
  Session session=HibernateSessionFactory.getSession();
  String sql="select * from dept";//创建sql语句
  Query query = session.createSQLQuery(sql).addEntity(Dept.class);//addEntity是把sql变成hql,把表名变成类名
  System.out.println(query);
  int a=query.executeUpdate();
  System.out.println(a);
  
  
 }
}

 

4.对象查询

package com.model.dao;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;

import com.comm.HibernateSessionFactory;
import com.model.pojo.Emp;

public class EmpDao {
 public static void main(String[] args) {
  EmpDao edao=new EmpDao();
  edao.selEmp();
  
 }
 //QBC查询,也叫对象查询
 public void selEmp(){
  Session session=HibernateSessionFactory.getSession();
  //第一个参数是个路径,第二个参数是别名(String associationPath, String alias)
  Criteria c = session.createCriteria(Emp.class, "e");//创建QBC查询语句,并给则个对象起个别名e
  //第一个参数是路径,第二个参数是连接类型(例如左外连接,内连接等)(String associationPath, int joinType)
  //连接类型中的1是Criteria接口的实现类CriteriaSpecification(查看源代码)中的一个常量的值,
  c.createCriteria("e.dept",1);//左连接
  c.add(Restrictions.eq("e.ename","喜洋洋"));
  List elist = c.list();
  for(Emp e:elist){
   System.out.println(e.getEname());
   System.out.println(e.getDept().getDname());
  }
 }
 
 

}

 

 

你可能感兴趣的:(hibernate)