【JavaEE学习笔记】Hibernate_03_缓存机制,自定义通用HibernateDAO工具类

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  最近最少使用的

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

查询数据库


猜你喜欢

转载自blog.csdn.net/wpf719971425/article/details/79058703