【JavaEE学习笔记】Hibernate_03_缓存机制,自定义通用HibernateDAO工具类
2018-01-14 21:50
736 查看
Hibernate_03
A.Hibernate缓存
1.一级缓存
一级缓存是Session缓存,属于事务范围的缓存,由hibernate管理的
只要应用程序通过Session接口来执行CRUD操作
Hibernate就会启用一级缓存,把数据库中的数据以对象的形式拷贝到缓存中
对于批量更新和批量删除操作,如果不希望启用第一级缓存
可以绕过Hibernate API,直接使用JDBC API操作
一级缓存中对象的生命周期为:当session关闭后,就自动销毁
2.二级缓存
二级缓存是SessionFactory级别的缓存,属于进程或群集范围的缓存
二级缓存是可选插件,默认不启用
就是查询的时候会把结果缓存到二级缓存中
如果同一个sessionFactory创建的其他session执行了相同的操作
hibernate就会从二级缓存中拿结果,而不会再连接数据库
主要使用第三方缓存插件,如使用Ehcache二级缓存实现
使用步骤:
a.导入Hibernate和mysql数据库驱动以及druid的jar包
b.导入二级缓存的插件包:optional下ehcache中三个jar
c.在主配置文件中hibernate.cfg.xml 添加配置信息
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 数据库信息要改 -->
<property name="diverClassName">com.mysql.jdbc.Driver</property>
<property name="url">jdbc:mysql://localhost:3306/test</property>
<property name="username">root</property>
<property name="password">root</property>
<!-- 添加durid驱动 -->
<property name="hibernate.connection.provider_class">com.alibaba.druid.support.hibernate.DruidConnectionProvider</property>
<!-- mysql方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL57Dialect</property>
<!-- 创建表方式为自动更新 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 是否显示sql语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 是否格式化 -->
<property name="hibernate.format_sql">true</property>
<!-- 配置连接池初始化大小 -->
<property name="initialSize">2</property>
<!-- 最小空闲连接数 -->
<property name="minIdle">1</property>
<!-- 最大连接数 -->
<property name="maxActive">300</property>
<!-- 获取连接等待超时的时间,单位:毫秒 -->
<property name="maxWait">60000</property>
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis">60000</property>
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis">300000</property>
<!-- 开启二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<!-- 映射位置 -->
<mapping resource="org/xxxx/pojo/UserInfo.hbm.xml" />
</session-factory>
</hibernate-configuration>
d.在src根目录下配置ehcache.xml
name:cache唯一标识
eternal:缓存是否永久有效
maxElementsInMemory:内存中最大缓存对象数
overflowToDisk(true,false):缓存对象到最大数后,写到硬盘中
diskPersistent:硬盘持久化
timeToIdleSeconds:缓存清除时间
timeToLiveSeconds:缓存存活时间
memoryStoreEvictionPolicy:缓存清空策略
FIFO:first in first out 先进先出
LFU: Less Frequently Used 一直以来最少被使用的
LRU:Least Recently Used 最近最少使用的
e.在需要被缓存的对象中hbm文件中的<class>标签下添加<cache>子标签
UserInfo.java
UserInfo.hbm.xml
f.测试
第一次查询会生成查询语句,并查询数据库
再次查询都会从cache中获取数据
3.查询缓存
Hibernate还为查询结果提供了一个查询缓存,它依赖于第二级缓存
在配置文件中开启查询缓存
需要在所有的查询方法中设置setCacheable(true)
测试
可以看出,第二次查询没有连接数据库,直接从缓存中拿到
B.通用HibernateDAO工具类(配置文件和UserInfo参照上面的)
1.获取Session工具类
HibernateUtil类,简化获取和关闭Session,使用到了单例模式
2.通用DAO接口
3.通用接口子类
具体抽象实现类可以实现自己的接口,同时继承该子类
使用抽象类不能被实例化,要使用该实现类必须继承
子实现类
子实现类的子类
4.测试
查询数据库
A.Hibernate缓存
1.一级缓存
一级缓存是Session缓存,属于事务范围的缓存,由hibernate管理的
只要应用程序通过Session接口来执行CRUD操作
Hibernate就会启用一级缓存,把数据库中的数据以对象的形式拷贝到缓存中
对于批量更新和批量删除操作,如果不希望启用第一级缓存
可以绕过Hibernate API,直接使用JDBC API操作
一级缓存中对象的生命周期为:当session关闭后,就自动销毁
2.二级缓存
二级缓存是SessionFactory级别的缓存,属于进程或群集范围的缓存
二级缓存是可选插件,默认不启用
就是查询的时候会把结果缓存到二级缓存中
如果同一个sessionFactory创建的其他session执行了相同的操作
hibernate就会从二级缓存中拿结果,而不会再连接数据库
主要使用第三方缓存插件,如使用Ehcache二级缓存实现
使用步骤:
a.导入Hibernate和mysql数据库驱动以及druid的jar包
b.导入二级缓存的插件包:optional下ehcache中三个jar
c.在主配置文件中hibernate.cfg.xml 添加配置信息
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 数据库信息要改 -->
<property name="diverClassName">com.mysql.jdbc.Driver</property>
<property name="url">jdbc:mysql://localhost:3306/test</property>
<property name="username">root</property>
<property name="password">root</property>
<!-- 添加durid驱动 -->
<property name="hibernate.connection.provider_class">com.alibaba.druid.support.hibernate.DruidConnectionProvider</property>
<!-- mysql方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL57Dialect</property>
<!-- 创建表方式为自动更新 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 是否显示sql语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 是否格式化 -->
<property name="hibernate.format_sql">true</property>
<!-- 配置连接池初始化大小 -->
<property name="initialSize">2</property>
<!-- 最小空闲连接数 -->
<property name="minIdle">1</property>
<!-- 最大连接数 -->
<property name="maxActive">300</property>
<!-- 获取连接等待超时的时间,单位:毫秒 -->
<property name="maxWait">60000</property>
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis">60000</property>
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis">300000</property>
<!-- 开启二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<!-- 映射位置 -->
<mapping resource="org/xxxx/pojo/UserInfo.hbm.xml" />
</session-factory>
</hibernate-configuration>
d.在src根目录下配置ehcache.xml
name:cache唯一标识
eternal:缓存是否永久有效
maxElementsInMemory:内存中最大缓存对象数
overflowToDisk(true,false):缓存对象到最大数后,写到硬盘中
diskPersistent:硬盘持久化
timeToIdleSeconds:缓存清除时间
timeToLiveSeconds:缓存存活时间
memoryStoreEvictionPolicy:缓存清空策略
FIFO:first in first out 先进先出
LFU: Less Frequently Used 一直以来最少被使用的
LRU:Least Recently Used 最近最少使用的
<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" updateCheck="false"> <defaultCache maxElementsInMemory="1000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"></defaultCache> <cache name="userCache" eternal="false" maxElementsInMemory="1000" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="3600" timeToLiveSeconds="3600" memoryStoreEvictionPolicy="LFU"></cache> </ehcache>
e.在需要被缓存的对象中hbm文件中的<class>标签下添加<cache>子标签
UserInfo.java
package org.xxxx.pojo; import java.io.Serializable; public class UserInfo implements Serializable { private static final long serialVersionUID = 1L; private int id; private String username; private String password; public UserInfo() { super(); // TODO Auto-generated constructor stub } public UserInfo(String username, String password) { super(); this.username = username; this.password = password; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "UserInfo [id=" + id + ", username=" + username + ", password=" + password + "]"; } }
UserInfo.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Generated 2018-1-13 20:10:19 by Hibernate Tools 3.5.0.Final --> <hibernate-mapping package="org.xxxx.pojo"> <class name="UserInfo" table="USERINFO"> <!-- 配置缓存权限为只读 --> <cache usage="read-only"></cache> <id name="id" type="int"> <column name="UID" /> <!-- 自增长 --> <generator class="native" /> </id> <property name="username" type="java.lang.String"> <column name="USERNAME" /> </property> <property name="password" type="java.lang.String"> <column name="PASSWORD" /> </property> </class> </hibernate-mapping>
f.测试
package org.xxxx.pojo; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class Test_01 { public static void main(String[] args) { // 加载配置文件 Configuration config = new Configuration().configure(); // 创建Session工厂 SessionFactory factory = config.buildSessionFactory(); // 获取Session Session session = factory.openSession(); // 获取id为3的UserInfo,默认从Session缓存中尝试加载 UserInfo uInfo = session.get(UserInfo.class, 3); System.out.println(uInfo); System.out.println("-------------------------------------"); // 再次查询 UserInfo uInfo2 = session.get(UserInfo.class, 3); System.out.println(uInfo2); System.out.println("-------------------------------------"); // 释放资源 session.close(); // 再次开启 // 获取Session Session session2 = factory.openSession(); UserInfo uInfo3 = session2.get(UserInfo.class, 3); System.out.println(uInfo3); session2.close(); } }
第一次查询会生成查询语句,并查询数据库
再次查询都会从cache中获取数据
3.查询缓存
Hibernate还为查询结果提供了一个查询缓存,它依赖于第二级缓存
在配置文件中开启查询缓存
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- 数据库信息要改 --> <property name="diverClassName">com.mysql.jdbc.Driver</property> <property name="url">jdbc:mysql://localhost:3306/test</property> <property name="username">root</property> <property name="password">root</property> <!-- 添加durid驱动 --> <property name="hibernate.connection.provider_class">com.alibaba.druid.support.hibernate.DruidConnectionProvider</property> <!-- mysql方言 --> <property name="hibernate.dialect">org.hibernate.dialect.MySQL57Dialect</property> <!-- 创建表方式为自动更新 --> <property name="hibernate.hbm2ddl.auto">update</property> <!-- 是否显示sql语句 --> <property name="hibernate.show_sql">true</property> <!-- 是否格式化 --> <property name="hibernate.format_sql">true</property> <!-- 配置连接池初始化大小 --> <property name="initialSize">2</property> <!-- 最小空闲连接数 --> <property name="minIdle">1</property> <!-- 最大连接数 --> <property name="maxActive">300</property> <!-- 获取连接等待超时的时间,单位:毫秒 --> <property name="maxWait">60000</property> <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> <property name="timeBetweenEvictionRunsMillis">60000</property> <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> <property name="minEvictableIdleTimeMillis">300000</property> <!-- 开启查询缓存 --> <property name="hibernate.cache.use_query_cache">true</property> <!-- 开启二级缓存 --> <property name="hibernate.cache.use_second_level_cache">true</property> <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property> <!-- 映射位置 --> <mapping resource="org/xxxx/pojo/UserInfo.hbm.xml" /> </session-factory> </hibernate-configuration>
需要在所有的查询方法中设置setCacheable(true)
测试
package org.xxxx.pojo; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.hibernate.query.Query; public class Test_01 { public static void main(String[] args) { // 加载配置文件 Configuration config = new Configuration().configure(); // 创建Session工厂 SessionFactory factory = config.buildSessionFactory(); // 获取Session Session session = factory.openSession(); // 定义hql语句,获取id为1的信息 String hql = "from UserInfo where id=1"; // 执行 @SuppressWarnings("unchecked") Query<UserInfo> query = session.createQuery(hql).setCacheable(true); // 获取结果 UserInfo uInfo = query.uniqueResult(); System.out.println(uInfo); // 释放资源 session.close(); System.out.println("-----------------------------------------------------"); // 再次执行上面代码 // 获取Session Session session1 = factory.openSession(); // 执行 @SuppressWarnings("unchecked") Query<UserInfo> query1 = session1.createQuery(hql).setCacheable(true); // 获取结果 UserInfo uInfo1 = query1.uniqueResult(); System.out.println(uInfo1); // 释放资源 session1.close(); } }
可以看出,第二次查询没有连接数据库,直接从缓存中拿到
B.通用HibernateDAO工具类(配置文件和UserInfo参照上面的)
1.获取Session工具类
HibernateUtil类,简化获取和关闭Session,使用到了单例模式
package org.xxxx.util; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtil { // 线程本地变量,存放线程对象session private static final ThreadLocal<Session> threadLocal = new ThreadLocal<>(); private static final SessionFactory factory; // 初始化,保证只有一个factory,防止出现多线程问题 static { Configuration config = new Configuration().configure(); factory = config.buildSessionFactory(); } // 私有构造,不让创建对象 private HibernateUtil() { } // 获取Session public static Session getSession() { // 从线程本地变量中获取当前线程对象 Session session = threadLocal.get(); // 判断是否存在 if (session == null) { // 为空,创建一个 session = factory.openSession(); // 放置到线程变量中 threadLocal.set(session); } return session; } // 关闭Session public static void closeSession() { // 获取session Session session = threadLocal.get(); // 非空判断 if (session != null) { session.close(); // 将线程变量置空 threadLocal.set(null); } } }
2.通用DAO接口
package org.xxxx.util; import java.io.Serializable; import java.util.List; public interface BaseDAO<T> { // 保存 public Serializable save(final T entity); // 更新,必须带有主键 public void update(final T entity); // 保存或更新 public void saveOrUpdate(final T entity); // 删除,必须带有主键 public void delete(final T entity); // 通过对象标识符获取对象 public T findById(final Serializable oid); // 返回所有对象 public List<T> findAll(); // 获取分页记录 List<T> findByPage(String hql, int start, int pageSize); // 通用查询方法:queryName是命名查询名字 public List<T> executeQuery(String hql, Object... params); // 通用查询方法:queryName是命名查询名字 public List<T> executeNamedQuery(String queryName, Object... params); // 通用更新方法:queryName是命名查询名字 public int executeUpdate(String hql, Object... params); // 通用更新方法:queryName是命名查询名字 public int executeNamedUpdate(String hqlName, Object... params); }
3.通用接口子类
具体抽象实现类可以实现自己的接口,同时继承该子类
使用抽象类不能被实例化,要使用该实现类必须继承
子实现类
package org.xxxx.util; import java.io.Serializable; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import org.hibernate.query.Query; // 抽象类,不能被实例化,要使用只能继承 public abstract class BaseDAPOImpl<T> implements BaseDAO<T> { // 存储泛型的实际参数,即子类所指定的T所对应的类型 // Hibernate底层通过反射实现,所以T即为所对应的类的类型 private Class<T> clazz; @SuppressWarnings("unchecked") public BaseDAPOImpl() { // 返回实际泛型类型 Type type = getClass().getGenericSuperclass(); ParameterizedType types = (ParameterizedType) type; Type[] typeArr = types.getActualTypeArguments(); this.clazz = (Class<T>) typeArr[0].getClass(); } @Override public Serializable save(T entity) { Serializable uid = HibernateUtil.getSession().save(entity); return uid; } @Override public void update(T entity) { HibernateUtil.getSession().update(entity); } @Override public void saveOrUpdate(T entity) { HibernateUtil.getSession().saveOrUpdate(entity); } @Override public void delete(T entity) { HibernateUtil.getSession().delete(entity); } @Override public T findById(Serializable oid) { return HibernateUtil.getSession().get(clazz, oid); } @Override public List<T> findAll() { // 通过反射获取类名 @SuppressWarnings("unchecked") Query<T> query = HibernateUtil.getSession().createQuery("from" + clazz.getSimpleName()); return query.getResultList(); } @Override public List<T> findByPage(String hql, int start, int pageSize) { @SuppressWarnings("unchecked") Query<T> query = HibernateUtil.getSession().createQuery(hql); // 设置开始id以及每页显示数量 query.setFirstResult(start); query.setMaxResults(pageSize); return query.getResultList(); } @Override public List<T> executeQuery(String hql, Object... params) { @SuppressWarnings("unchecked") Query<T> query = HibernateUtil.getSession().createQuery(hql); // 获取参数长度 int len = params.length; // 非空判断 if (len != 0) { for (int i = 0; i < len; i++) { // 设置第i个参数 query.setParameter(i, params[i]); } } return query.getResultList(); } @Override public List<T> executeNamedQuery(String queryName, Object... params) { @SuppressWarnings("unchecked") Query<T> query = HibernateUtil.getSession().getNamedQuery(queryName); // 设置参数 int len = params.length; if (len != 0) { for (int i = 0; i < len; i++) { query.setParameter(i, params[i]); } } return query.getResultList(); } @Override public int executeUpdate(String hql, Object... params) { @SuppressWarnings("unchecked") Query<T> query = HibernateUtil.getSession().createQuery(hql); int len = params.length; if (len != 0) { for (int i = 0; i < len; i++) { query.setParameter(i, params[i]); } } return query.executeUpdate(); } @Override public int executeNamedUpdate(String hqlName, Object... params) { @SuppressWarnings("unchecked") Query<T> query = HibernateUtil.getSession().getNamedQuery(hqlName); int len = params.length; if (len != 0) { for (int i = 0; i < len; i++) { query.setParameter(i, params[i]); } } return query.executeUpdate(); } }
子实现类的子类
package org.xxxx.util; // 可以扩展父类的功能 public class UserInfoDaoImpl<UserInfo> extends BaseDAPOImpl<UserInfo> { }
4.测试
package org.xxxx.util; import org.hibernate.Transaction; import org.xxxx.pojo.UserInfo; public class TestDao { public static void main(String[] args) { // 创建对象 UserInfoDaoImpl<UserInfo> impl = new UserInfoDaoImpl<>(); // 开启事物 Transaction action = HibernateUtil.getSession().beginTransaction(); // 添加数据 UserInfo uInfo = new UserInfo("yangqi", "123456"); impl.save(uInfo); // 提交事物 action.commit(); // 关闭 HibernateUtil.closeSession(); } }
查询数据库
相关文章推荐
- Hibernate学习笔记 -- day05 缓存、快照机制、对象状态
- Hibernate学习笔记之----理解对象的持久性与一级缓存机制
- 【django 学习笔记】14-缓存机制
- 【JavaEE学习笔记】JDBC_03_批处理,获取自增长键值,DBCP,C3P0,DBUtils
- 【JavaEE】javaEE学习笔记之---hibernate框架01
- 【JavaEE学习笔记】Hibernate_02_连接池,HQL
- Hibernate学习笔记(4)之缓存
- Cocos2d-x学习笔记(十)—— 缓存机制
- Java 学习笔记03:Spring 3.0 核心机制 IoC
- [原创]java WEB学习笔记78:Hibernate学习之路---session概述,session缓存(hibernate 一级缓存),数据库的隔离级别,在 MySql 中设置隔离级别,在 Hibernate 中设置隔离级别
- Hibernate笔记——缓存机制详细分析
- Struts2学习笔记03----Struts2中的VO、ModelDriven机制及其运用
- Hibernate 学习笔记03 --ID生成策略
- Hibernate学习---缓存机制
- android 学习笔记:自定义通用ListView/GridView,实现ListAdapter 类
- hibernate笔记--缓存机制之 二级缓存(sessionFactory)和查询缓存
- PHP页面静态化学习笔记之三:使用PHP缓存机制完成静态化
- [原创]java WEB学习笔记93:Hibernate学习之路---Hibernate 缓存介绍,缓存级别,使用二级缓存的情况,二级缓存的架构集合缓存,二级缓存的并发策略,实现步骤,集合缓存,查询缓存,时间戳缓存
- Hibernate学习记录4 缓存机制
- Linux邻居协议 学习笔记 之五 通用邻居项的状态机机制 - __neigh_event_send()