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