首先说明一下最初什么都不懂想用hibernate二级缓存的原因:手头项目是个商城网站,大量用户访问,就想到缓存
在经朋友推荐,初步看了以下二级缓存的功能,看似很符合需求,但是实际构建后,应用起来却发现并不是那么回事。但
既然已经了解了,不妨就稍微记下来。
hibernate二级缓存不适用项目的原因是因为它只能缓存通过id查询的实体(类)对象,而我们通常查询商品是通过使用
hql来查询带有较为复杂关联的对象,而并不是简单的通过id查询对象。所以在本次项目中,我没有使用,因为我发出十几条
查询语句,只有一句是通过Id来查询的,使用二级缓存就显得没有什么意义。
说明:
hibernate的二级缓存策略一般是这样,查询的时候我们发出hql或者是sql,里面通常是带where条件以及排序、分组参数的,
查询到结果以后,hibernate会把查询到的所有结果根据id存到二级缓存里。
然后当hibernate根据id访问数据对象的时候,会先去session一级缓存找,找不到,再去二级缓存里找,如果缓存里面都没有,
就去数据库查了。
因为二级缓存是针对id的,所以对于我们这种需要比较多条件动态参数组合的情景就显得没有什么用处
虽然没用,但是也要记下怎么做的。
项目类型:WebProject
项目环境:spring4.2.9-mvc、hibernate4.3.11.Final
我们需要到hibernate官方下载包,这里可以直接百度hibernate就可以。
我下载的是:hibernate-release-4.3.11.Final
是个压缩文件,解压后,hibernate-release-4.3.11.Final\lib\optional\ehcache
把上面的路径下的jar包导入项目中。
spring-xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">
<!-- 引用properties文件里的配置 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:config/setting.properties</value>
</list>
</property>
</bean>
<!-- 启用@Resource功能 -->
<context:annotation-config />
<!-- 启用@Repository、@Service、@Controller、@Component -->
<context:component-scan base-package="cn.com.aa"/>
<!-- 配置数据源:jndi方式 -->
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>${jndiName}</value>
</property>
</bean>
<!-- annotation方式配置sessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="cn.com.aa"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<strong><span style="color:#3366ff;"><prop key="hibernate.show_sql">true</prop><span style="white-space:pre"> </span><-- 这里是开启控制台输出hibernate向数据库发出sql的功能--></span></strong>
<-- 这里是开启控制台输出hibernate向数据库发出sql的功能-->
<prop key="hibernate.format_sql">false</prop>
<!-- <prop key="hibernate.hbm2ddl.auto">update</prop>-->
<prop key="hibernate.jdbc.fetch_size">25</prop>
<!-- 没有下面的配置,在JUnit测试时会报错 -->
<prop key="javax.persistence.validation.mode">none</prop>
<!-- 开启缓存 -->
<prop key="hibernate.cache.use_query_cache">true</prop>
<!--开启二级缓存-->
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<!--指定二级缓存的提供类-->
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
<!--指定二级缓存配置文件的位置-->
<prop key="hibernate.cache.provider_configuration_file_resource_path">classpath:config/ehcache.xml</prop>
<!-- 强制Hibernate以更人性化的格式将数据存入二级缓存 -->
<prop key="hibernate.cache.use_structured_entries">true</prop>
<!-- Hibernate将收集有助于性能调节的统计数据 -->
<prop key="hibernate.generate_statistics">true</prop>
</props>
</property>
</bean>
<!-- 配置事务,使用spring自带的hibernate事务管理器 -->
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="txManager"/>
<!-- spring自带的hibernate工具类 -->
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate4.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!--启动JSON格式的配置 -->
<mvc:annotation-driven>
<mvc:message-converters>
<bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=utf-8</value>
<value>text/html;charset=UTF-8</value>
<value>text/json;charset=UTF-8</value>
<value>application/json;charset=utf-8</value>
<value>application/pdf;charset=ISO8859-1</value>
</list>
</property>
<property name="objectMapper">
<bean class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="dateFormat">
<bean class="java.text.SimpleDateFormat">
<constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss"/>
</bean>
</property>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<!-- 把ByteArray加在Json前面 -->
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<bean id="jsonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" >
<property name = "supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</list>
</property>
</bean>
</beans>
配置完了之后,我们就进入我们的实体类。(我使用注解映射实体,不是用hibernate.xml配的)
/**
* 管理员用户表
*/
@Entity
@Table(name="T_ADMIN_USER")
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY) //主要要加的就是这行注释了
public class AdminUser implements Serializable {
private static final long serialVersionUID = 1L;
private String id; //主键
private String loginName; //用户名
private String password; //密码
private Integer userType; //用户类型
private Date createTime; //创建时间
private String userName; //用户真实姓名
private String email; //邮箱
private String mobile; //手机
private Integer active; //有效状态,1=有效(默认),0=无效
private Integer delFlag; //删除标识,0=可用(默认),1=已删除
public AdminUser() {
}
然后如果有外键的话,也要加
@ManyToOne(fetch = FetchType.EAGER)
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
@JoinColumn(name = "F_CLAUSE_ID", nullable = false)
public Clause getClause() {
return clause;
}
完成后,我是在dao的实现中添加的,由于有一个继承和实现的基础类和接口,所以我重写了其中的方法:
要是不写也有点效果,可以少点因为外键关联查询多发出的sql请求。
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import cn.com.aa.dao.ProductDao;
import cn.com.aa.entity.Product;
@Repository("productDao")
public class ProductDaoHibernate extends GenericDaoHibernate<Product, String> implements
ProductDao {
<span style="color:#ff6666;">@Autowired
private SessionFactory sessionFactory;
private Session getCurrentSession() {
return this.sessionFactory.getCurrentSession();
}
@Override
public Product findById(String id) {
return (Product)this.getCurrentSession().get(Product.class, id);
}</span>
}
这样就可以了。
我们可以打开hibernate的配置,在控制台输出hibernate发出的sql来查看是否缓存好了。
我们可以通过eclipse或者是MyEclipse的控制台看到,在我们前端第二次发起同一个请求的时候,
后台并没有像第一次前端发出请求时候,打出那个通过id查询的sql语句,说明hibernate进行数据库操作的时候,
使用了hibernate的二级缓存,所以没有从数据获取。
这里是最后的补充:经过后续的实践,发现实际上二级缓存可以减少hibernate发出SQL语句请求,如果有比较多的主外键需要一起查询的话(这里可能是我不会优化),只使用实体类注解那样的配置还是可以减少一部分的数据库请求。