1.導入jar包
ehcache-core-2.4.5.jar
ehcache-spring-annotations-1.2.0.jar(使用spring注解的形式配置時需要引入的jar包,依賴于guava)
ehcache-web-2.0.4.jar(做頁面緩存需要用到)
guava-r09.jar(google推出可以幫助你寫出更優雅代碼的工具,和apache-commons差不多)
hibernate-ehcache-4.2.21.Final.jar(hibernate對于ehcache的支援)
2.編寫ehcache.xml
将下載下傳ehcache時附帶的ehcache.xsd引入到工程中,我放在了src/config目錄下
在classpath路徑下建立xml檔案,命名為ehcache.xml,然後其格式可以參考下載下傳ehcache時附帶的ehcache.xml,以下是我的配置
<?xml version="1.0" encoding="UTF-8"?>
<!--制定xsd的位置,這個xsd需要自己下載下傳,賊坑,
網上的寫的是用http://ehcache.org/ehcache.xsd 但是idea一直在報錯,
最新版的是有附帶ehcache.xsd的,然後自己加就好了,我發現我用的這個版本的jar如果點開
也有一個ehcache-*的一個配置檔案的,裡面的ehcache.xsd是可以使用的!但是我死活找不到,
沒辦法隻能自己下載下傳自己加了,網上的方法都沒有什麼好的,手動大笑-->
<!--updateCheck不要設定為true,否則每一次的開啟都會自動檢查更新,導緻運作很慢-->
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="config/ehcache.xsd"
updateCheck="false">
<!--緩存儲存位址-->
<diskStore path="java.io.tmpdir"/>
<!--預設的緩存配置-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="30"
timeToLiveSeconds="30"
overflowToDisk="false"/>
<!--自定義緩存配置-->
<!--
1.必須要有的屬性:
name: cache的名字,用來識别不同的cache,必須惟一。
maxElementsInMemory: 記憶體管理的緩存元素數量最大限值。
maxElementsOnDisk: 硬碟管理的緩存元素數量最大限值。預設值為0,就是沒有限制。
eternal: 設定元素是否持久話。若設為true,則緩存元素不會過期。
overflowToDisk: 設定是否在記憶體填滿的時候把資料轉到磁盤上。
2.下面是一些可選屬性:
timeToIdleSeconds: 設定元素在過期前空閑狀态的時間,隻對非持久性緩存對象有效。預設值為0,值為0意味着元素可以閑置至無限長時間。
timeToLiveSeconds: 設定元素從建立到過期的時間。其他與timeToIdleSeconds類似。
diskPersistent: 設定在虛拟機重新開機時是否進行磁盤存儲,預設為false.(我的直覺,對于安全小型應用,宜設為true)。
diskExpiryThreadIntervalSeconds: 通路磁盤線程活動時間。
diskSpoolBufferSizeMB: 存入磁盤時的緩沖區大小,預設30MB,每個緩存都有自己的緩沖區。
memoryStoreEvictionPolicy: 元素逐出緩存規則。共有三種,Recently Used (LRU)最近最少使用,為預設。
First In First Out (FIFO),先進先出。Less Frequently Used(specified as LFU)最少使用
-->
<cache name="sampleCache"
maxElementsInMemory="10000"
maxElementsOnDisk="1000"
eternal="false"
overflowToDisk="true"
diskSpoolBufferSizeMB="20"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU" />
</ehcache>
3.修改applicationContext.xml
修改applicationContext.xml用來內建ehcache。
<!--開啟ehcache注解掃描-->
<ehcache:annotation-driven />
<!--ehcache工廠的配置-->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml"/>
</bean>
<!--配置cache-manager-->
<ehcache:config cache-manager="cacheManager">
<ehcache:evict-expired-elements interval="60" />
</ehcache:config>
配置完這個之後,整個applicationContext.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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.2.xsd
http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.1.xsd">
<!--自動掃描包-->
<context:component-scan base-package="cn.limbo">
<!--不要将Controller掃進來,否則aop無法使用-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--使Aspect注解起作用,自動為比對的類生成代理對象-->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!--開啟ehcache注解掃描-->
<ehcache:annotation-driven />
<!--ehcache工廠的配置-->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml"/>
</bean>
<!--配置cache-manager-->
<ehcache:config cache-manager="cacheManager">
<ehcache:evict-expired-elements interval="60" />
</ehcache:config>
<!--引入properties-->
<context:property-placeholder location="classpath:hibernate.properties"/>
<!--配置資料源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${dataSource.username}"/>
<property name="password" value="${dataSource.password}"/>
<property name="jdbcUrl" value="${dataSource.url}"/>
<property name="driverClass" value="${dataSource.driverClassName}"/>
</bean>
<!--<!–sessionFactory–>-->
<!--<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">-->
<!--<!– 配置資料源屬性 –>-->
<!--<property name="dataSource" ref="dataSource"/>-->
<!--<!– 配置掃描的實體包(pojo) –>-->
<!--<property name="namingStrategy">-->
<!--<bean class="org.hibernate.cfg.ImprovedNamingStrategy"/>-->
<!--</property>-->
<!--<property name="packagesToScan" value="cn.limbo.entity"/>-->
<!--<property name="hibernateProperties">-->
<!--<props>-->
<!--<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>-->
<!--<prop key="hibernate.show_sql">true</prop>-->
<!--<prop key="hibernate.format_sql">true</prop>-->
<!--<prop key="hibernate.hbm2ddl.auto">update</prop>-->
<!--</props>-->
<!--</property>-->
<!--</bean>-->
<bean id="persistenceProvider"
class="org.hibernate.ejb.HibernatePersistence"/>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="MYSQL"/>
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
<!--jpa工廠-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<!--資料源-->
<property name="dataSource" ref="dataSource"/>
<!--持久層提供者-->
<property name="persistenceProvider" ref="persistenceProvider"/>
<!--擴充卡-->
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaDialect" ref="jpaDialect"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${dataSource.dialect}</prop>
<prop key="hibernate.connection.driver_class">${dataSource.driverClassName}</prop>
<prop key="hibernate.max_fetch_depth">3</prop>
<prop key="hibernate.jdbc.fetch_size">18</prop>
<prop key="hibernate.jdbc.batch_size">10</prop>
<prop key="hibernate.hbm2ddl.auto">${dataSource.hbm2ddl.auto}</prop>
<prop key="hibernate.show_sql">${dataSource.show_sql}</prop>
<prop key="hibernate.format_sql">${dataSource.format_sql}</prop>
<!--做bean validation的也就是對你的輸入的資料進行語義的驗證-->
<prop key="javax.persistence.validation.mode">none</prop>
</props>
</property>
<property name="packagesToScan">
<list>
<value>cn.limbo.entity</value>
</list>
</property>
</bean>
<jpa:repositories base-package="cn.limbo.dao"
entity-manager-factory-ref="entityManagerFactory"
transaction-manager-ref="transactionManager"/>
<!-- 配置Hibernate 的事物管理器 -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
4.使用ehcache
配置完成之後使用ehcache就比較簡單了,隻要在需要緩存的地方加上@Cacheable标簽就好了
但是需要注意的是,最好是在做查詢的方法裡使用ehcache,在做增删改的時候要清除緩存,這點比較重要,否則在并發情況下會出現資料的髒讀和幻讀之類的東西
一般在dao中的service層引入ehcache,使用方法如下:
package cn.limbo.service.impl;
import cn.limbo.dao.UserDao;
import cn.limbo.entity.User;
import cn.limbo.service.UserService;
import com.googlecode.ehcache.annotations.Cacheable;
import com.googlecode.ehcache.annotations.TriggersRemove;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* Created by limbo on 2016/11/26.
*/
@Service("userService")
@Transactional
public class UserServiceImpl implements UserService{
@Autowired
private UserDao userDao;
@Override
@Cacheable(cacheName = "sampleCache")
public User getUserByID(int ID) {
return userDao.getUserByID(ID);
}
@Override
@Cacheable(cacheName = "sampleCache")
public List<User> getAllUsers() {
return userDao.getAllUsers();
}
@Override
@TriggersRemove(cacheName="sampleCache",removeAll=true)//清除緩存
public void addUser(String name,String password) {
User user = new User(name,password);
userDao.save(user);
}
@Override
@TriggersRemove(cacheName="sampleCache",removeAll=true)//清除緩存
public void deleteUserByID(int ID) {
userDao.delete(ID);
}
@Override
@TriggersRemove(cacheName="sampleCache",removeAll=true)//清除緩存
public void updateUser(User user) {
userDao.update(user.getID(),user.getName(),user.getPassword());
}
@Override
public boolean isExist(String userName) {
if(userDao.getUserByName(userName) != null)
return true;
return false;
}
}
5.總結
發現有兩個坑點: 1.ehcache.xsd找不到,一開始網上給的解決方案都是改成http://ehcahce.org/ehcahce.xsd,但是我發現這樣還是有問題的,後來發現我下載下傳ehcache的時候附帶了ehcahce.xsd,引入就好咯 2.使用cache的時候,@Cacheable(cacheName=""),使用的是在ehcache.xml自定義配置的ehcache名字,而不是在applicationContext.xml裡面配置的bean的名字
源碼我放到了github上: https://github.com/NetFilx/Google-Authenticator