Hibernate补充缓存与注解

1 hibernate缓存

概念

通过内存/硬盘存储查询结果--缓存
当再次执行查询时 先判断缓存中是否有查询的结果 如果有就直接使用 如果没有再去访问数据库
缓存作用:1 提高查询效率  2 减少数据库服务器的压力
缓存缺点:线程并发问题

1.1一级缓存:session级别的缓存

简单理解:
	当hibernate创建session时,与此session关联一个对象(map类型的对象)
    执行get、load、list、iterator方法时 查询的对象的id作为键 查询的对象作为值存储到此map中
    当执行session清空、关闭时会清空此缓存

适合缓存的数据

很少被修改的数据   
不是很重要的数据,允许出现偶尔并发的数据   
不会被并发访问的数据   
常量数据

不适合缓存的数据

经常被修改的数据   
绝对不允许出现并发访问的数据,如财务数据,绝对不允许出现并发   
与其他应用共享的数据

一级缓存案例

import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;
import sss.entity.Student;

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

public class TestPro {
    public static void main(String[] args) {
        //1 创建Configration对象 自动读取heibernate的核心配置文件
        Configuration conf = new Configuration();
        //2 读取核心配置文件
        conf.configure("sss/test/hibernatepro.xml");
        //3 通过Configuration创建sessionfactory对象
        SessionFactory factory = conf.buildSessionFactory();
        //4 获取连接
        Session session = factory.openSession();
        //5 创建事务
        Transaction transaction = session.beginTransaction();
        //6 开启事务
        transaction.begin();

        Student s1;
        s1 = (Student) session.get(Student.class, "1");
        System.out.println("第一次调用get查询数据库:" + s1);
        System.out.println("第二次调用get不查询数据库:" + s1);
        System.out.println("---------------------------------------------------------");
     ***session.clear();//清空session: 清空缓存方式1
        s1 = (Student) session.get(Student.class, "1");
        System.out.println("清空session输出:" + s1);
        System.out.println("---------------------------------------------------------");
     ***session.close();//关闭session: 清空缓存方式2
        session = factory.openSession();
        transaction = session.beginTransaction();
        s1 = (Student) session.get(Student.class, "1");
        System.out.println("关闭session输出:" + s1);
        System.out.println("--------------------------------------------------");
     ***session.evict(s1);//把对象s1从缓存中移除:清空缓存方式3
        s1 = (Student) session.get(Student.class, "1");
        System.out.println("从缓存移出输出:" + s1);
		System.out.println("--------------------------------------------------");
        
     ***//使用一级缓存1:get
     ***//使用一级缓存2:load
     ***//使用一级2缓存清空3:list
        List<Student> list;
        list = session.createQuery("from sss.entity.Student").list();
        for (Student s : list) {
            System.out.println(s);
        }
        System.out.println("--------------------------------------------------");
        //list方法不使用一级缓存  但结果会被一级缓存存储
        list = session.createQuery("from sss.entity.Student").list();
        for (Student s : list) {
            System.out.println(s);
        }
        System.out.println("--------------------------------------------------");
     ***//使用一级缓存4:iterator
        Iterator<Student> it;
        it=session.createQuery("from sss.entity.Student").iterate();
        while(it.hasNext()){
            System.out.println(it.next());
        }

        //7 事务提交
        transaction.commit();
        //8 关闭连接
        session.close();
    }
}

一级缓存总结

session.clear():清空一级缓存
session.close();清空一级缓存
session.evict(s);把对象s从一级缓存中清除

load\get\iterator方法可以使用一级缓存
list方法不能使用一级缓存 但查询结果会存储到一级缓存中
list方法是1次sql语句
iterator方法是1+n次sql语句   

1.2二级缓存:sessionfactory级别的缓存

  • hibernate没有实现二级缓存 需要第三方jar包的支持
导入jar包:ehcache-1.2.3.jar
  • 在src下创建一个ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
    <!-- 持久化保持对象的目录 -->
    <diskStore path="F:/hibernate_cache"/>
    <!-- maxElementsInMemory最多保存对象个数 -->
    <!-- eternal是否永久保存 -->
    <!-- timeToIdleSeconds:最多保存时间 单位秒 -->
    <!-- timeToLiveSeconds:最大存活时间 单位秒 -->
    <!-- overflowToDisk 是否持久化保持到硬盘上 -->
    <defaultCache
            maxElementsInMemory="2"
            eternal="true"
            timeToIdleSeconds="2"
            timeToLiveSeconds="2"
            overflowToDisk="true"/>
</ehcache>
  • 在核心配置中声明开始二级缓存
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>

    <session-factory>
        <!-- 指定方言 -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="connection.url">jdbc:mysql://localhost:3306/ssr</property>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.username">root</property>
        <property name="connection.password">root</property>
        <!-- 是否显示sql语句 -->
        <property name="show_sql">true</property>
        <!--自动创建表-->
        <property name="hbm2ddl.auto" >update</property>

        <!-- 配置二级缓存 -->
        <!-- 声明使用二级缓存 -->
        <property name="cache.use_second_level_cache">true</property>
        <!-- 声明二级缓存的供应商 -->
        <property name="cache.provider_class">
            org.hibernate.cache.EhCacheProvider
        </property>
        <!-- 声明Student1实体类要使用二级缓存:必须在导入类与表的映射文件的下面 -->
        <!--class-cache需要在mapping标签后面-->

        <!-- 导入类与表的映射文件-->
        <mapping resource="sss/entity/Stu.hbm.xml"/>
        <mapping resource="sss/entity/Tea.hbm.xml"/>
        <mapping resource="sss/entity/Husband.hbm.xml"/>
        <mapping resource="sss/entity/Wife.hbm.xml"/>
        <mapping resource="sss/entity/Goods.hbm.xml"/>
        <mapping resource="sss/entity/Order.hbm.xml"/>
        <mapping resource="sss/entity/Student.hbm.xml"/>

        <class-cache usage="read-only" class="sss.entity.Student" />
    </session-factory>
</hibernate-configuration>
  • 此时get load iterator可以使用二级缓存
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;
import org.hibernate.stat.SessionStatistics;
import sss.entity.Student;

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

public class TestPro {
    public static void main(String[] args) {
        //1 创建Configration对象 自动读取heibernate的核心配置文件
        Configuration conf = new Configuration();
        //2 读取核心配置文件
        conf.configure("sss/test/hibernatepro.xml");
        //3 通过Configuration创建sessionfactory对象
        SessionFactory factory = conf.buildSessionFactory();
        //4 获取连接
        Session session = factory.openSession();
        //5 创建事务
        Transaction transaction = session.beginTransaction();
        //6 开启事务
        transaction.begin();
        
        Student s1;
        s1=(Student)session.get(Student.class,"1");
        List<Student> list;
        list=session.createQuery("from sss.entity.Student").list();
        for(Student s:list){
            System.out.println(s);
        }
        System.out.println("--------------------------------");
        session.close();
        session=factory.openSession();
        s1=(Student)session.get(Student.class,"3");//1.get使用了二级缓存
        s1=(Student)session.load(Student.class,"3"); //2.load使用了二级缓存
        System.out.println(s1);
        System.out.println("--------------------------------");
        Iterator<Student> it;//3.iterator使用了二级缓存
        it=session.createQuery("from sss.entity.Student").iterate();
        while (it.hasNext()){
            System.out.println(it.next());
        }
        System.out.println("--------------------------------");
        //4.此时List不能使用二级缓存
        SessionStatistics ss=session.getStatistics();//获取二级缓存的统计信息
        System.out.println(ss);

        //7 事务提交
        transaction.commit();
        //8 关闭连接
        session.close();
    }
}

让list可以使用二级缓存

  • 在核心配置文件中添加配置
<!-- 开启query和criteria的list方法使用二级缓存 -->
<property name="cache.use_query_cache">true</property>
<!-- 开启二级缓存的统计 -->
<property name="generate_statistics">true</property>
  • 在使用缓存的对象的实体类mapper文件中添加配置
<!-- 指定当前class使用二级缓存 -->
<!--此配置的位置为class标签内的第一行-->
<cache usage="read-only"/>
  • 在获取query时 设置setCacheable为true
public class TestPro {
    public static void main(String[] args) {
        //1 创建Configration对象 自动读取heibernate的核心配置文件
        Configuration conf = new Configuration();
        //2 读取核心配置文件
        conf.configure("sss/test/hibernatepro.xml");
        //3 通过Configuration创建sessionfactory对象
        SessionFactory factory = conf.buildSessionFactory();
        //4 获取连接
        Session session = factory.openSession();
        //5 创建事务
        Transaction transaction = session.beginTransaction();
        //6 开启事务
        transaction.begin();

        List<Student> list;
        Queue queue;
        //声明使用二级缓存并把当前查询结果存储到二级缓存中,把本次查询的sql语句作为键 结果作为值 存储到二级缓存中
        list = session.createQuery("from sss.entity.Student").setCacheable(true).list();
        session.close();
        session = factory.openSession();
        list = session.createQuery("from sss.entity.Student").setCacheable(true).list();
        SessionStatistics ss = session.getStatistics();//获取二级缓存的统计信息
        System.out.println(ss);

        //7 事务提交
        transaction.commit();
        //8 关闭连接
        session.close();
    }
}

让list可以使用二级缓存

  • 在核心配置文件中添加配置
<!-- 开启query和criteria的list方法使用二级缓存 -->
<property name="cache.use_query_cache">true</property>
<!-- 开启二级缓存的统计 -->
<property name="generate_statistics">true</property>
  • 在使用缓存的对象的实体类mapper文件中添加配置
<!-- 指定当前class使用二级缓存 -->
<!--此配置的位置为class标签内的第一行-->
<cache usage="read-only"/>
  • 在获取query时 设置setCacheable为true
public class TestPro {
    public static void main(String[] args) {
        //1 创建Configration对象 自动读取heibernate的核心配置文件
        Configuration conf = new Configuration();
        //2 读取核心配置文件
        conf.configure("sss/test/hibernatepro.xml");
        //3 通过Configuration创建sessionfactory对象
        SessionFactory factory = conf.buildSessionFactory();
        //4 获取连接
        Session session = factory.openSession();
        //5 创建事务
        Transaction transaction = session.beginTransaction();
        //6 开启事务
        transaction.begin();

        List<Student> list;
        Queue queue;
        //声明使用二级缓存并把当前查询结果存储到二级缓存中,把本次查询的sql语句作为键 结果作为值 存储到二级缓存中
        list = session.createQuery("from sss.entity.Student").setCacheable(true).list();
        session.close();
        session = factory.openSession();
        list = session.createQuery("from sss.entity.Student").setCacheable(true).list();
        SessionStatistics ss = session.getStatistics();//获取二级缓存的统计信息
        System.out.println(ss);

        //7 事务提交
        transaction.commit();
        //8 关闭连接
        session.close();
    }
}

2 hibernate的注解形式

2.1 导入annotation相关的jar

  • ejb3-persistence.jar

  • hibernate-annotations.jar

  • hibernate-commons-annotations.jar

  • hibernate-entitymanager.jar

  • hibernate-validator.jar

2.2 相关sessionfactory的工具类中的configuration

//配置形式:
private  static Configuration configuration = new Configuration();  
//注解形式:
private  static Configuration configuration = new AnnotationConfiguration(); 

2.3 创建实体类 在实体类中使用注解

package sss.entity;

import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;

@Entity
@Table(name = "tab_person")
public class Person implements Serializable {

    @Id//此属性为主键列
    @Column(name = "p_id")  //对应的列名
    @GenericGenerator(name = "a1", strategy = "identity")//自定义一个自增策略生成器
    @GeneratedValue(generator = "a1")//指定自定义的id自增策略生成器
    private Integer pid;
    @Column(name = "p_name", unique = true)
    private String pname;
    @Column(name = "p_sex")//此注解可以加载属性上,也可以加在set方法上
    private String psex;
    @Column(name = "p_salary")
    private BigDecimal paslary;
    @Column(name = "p_birthday")
    private Date pbirthday;
	......
}

2.4 创建Person.hbm.xml

<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
    <!-- 指定类名 和 表名 -->
    <class name="sss.entity.Person" table="tab_person">
        <!-- 指定主键列对应的属性 -->
        <id name="pid" column="pid" type="int">
            <!-- 自增-->
            <generator class="identity"/>
        </id>
        <property name="pname" column="pname" type="string"/>
        <property name="psex" column="psex" type="string"/>
        <property name="paslary" column="paslary" type="java.math.BigDecimal"/>
        <property name="pbirthday" column="pbirthday" type="java.util.Date"/>

    </class>
</hibernate-mapping>

2.5 修改hibernate的核心配置文件

<!--自动创建表-->
<property name="hbm2ddl.auto" >update</property>
<!-- 注解没有mapper映射文件但需要引入实体类 -->
<mapping class="sss.entity.Person"/>

2.6 测试

public class TestPro {
    public static void main(String[] args) {
        //1 创建Configration对象 自动读取注解形式heibernate的核心配置文件
        Configuration conf = new AnnotationConfiguration();
        //2 读取核心配置文件
        conf.configure("sss/test/hibernatepro.xml");
        //3 通过Configuration创建sessionfactory对象
        SessionFactory factory = conf.buildSessionFactory();
        //4 获取连接
        Session session = factory.openSession();
        //5 创建事务
        Transaction transaction = session.beginTransaction();
        //6 开启事务
        transaction.begin();

        Person p1 = new Person("韩雪", "女", BigDecimal.valueOf(1111.5), new Date());
        session.save(p1);
        System.out.println(p1);
        
        //7 事务提交
        transaction.commit();
        //8 关闭连接
        session.close();
    }
}
posted @ 2021-12-07 20:58  RenVei  阅读(101)  评论(0编辑  收藏  举报