• Monthly Archives: 7月 2023

在SpringBoot中简单使用EhCache

很不巧,项目所在的环境中不允许使用Redis/Memcached等需要额外安装软件环境,因此只能使用EhCache。

基本介绍

EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认CacheProvider。Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持REST和SOAP api等特点。

使用方法

第一步:引入依赖

        <!-- ehcache 缓存依赖-->
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

第二步:创建配置

在application中加入以下配置:

spring:
  cache:
    type: ehcache
    ehcache:
      config: classpath:/ehcache.xml

创建配置文件ehcache.xml:

<?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"
                  overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="3600"
                  timeToLiveSeconds="3600" memoryStoreEvictionPolicy="LRU"/>
    <!--
       name:缓存名称。
       maxElementsInMemory:缓存最大个数。
       eternal:对象是否永久有效,一但设置了,timeout将不起作用。
       timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
       timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
       overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
       diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
       maxElementsOnDisk:硬盘最大缓存个数。
       diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
       diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
       memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
       clearOnFlush:内存数量最大时是否清除。
       -->
    <cache name="5s" maxElementsInMemory="100"
           overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="5" timeToLiveSeconds="5"
           memoryStoreEvictionPolicy="LRU"/>
</ehcache>

第三步:编写配置/工具类

创建工具类文件EhCacheUtil.java:

package com.ruoyi.common.core.ehcache;

import com.ruoyi.common.constant.CacheConstants;
import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.Collection;

@Configuration
public class EhCacheUtil {

    private static CacheManager manager;

    @Autowired
    public void setManager(CacheManager manager) {
        EhCacheUtil.manager = manager;
    }

    /**
     * 获取指定name的cache对象
     * @param cacheName
     * @return
     */
    private static Cache getCache(String cacheName) {
        net.sf.ehcache.CacheManager cacheManager = ((EhCacheCacheManager) manager).getCacheManager();
        if (!cacheManager.cacheExists(cacheName))
            cacheManager.addCache(cacheName);
        return cacheManager.getCache(cacheName);
    }

    /**
     * 获取指定cache缓存的指定key对象
     * @param cacheName
     * @param key
     * @return
     */
    public static <T> T get(String cacheName, Object key) {
        Cache cache = getCache(cacheName);
        Element e = cache.get(key);
        if(e!=null){
            return (T) e.getObjectValue();
        }
        return null;
    }

    /**
     *
     * @param cacheName
     * @param key
     * @param value
     * @param ttl   缓存自创建日期起至失效时的间隔时间(秒)
     * @param tti   缓存创建以后,最后一次访问缓存的日期至失效之时的时间间隔(秒)
     */
    public static void put(String cacheName, Object key, Object value, Integer ttl, Integer tti) {
        Cache cache = getCache(cacheName);
        Element e = new Element(key, value);
        //不设置则使用xml配置
        if (ttl != null)
            e.setTimeToLive(ttl);
        if (tti != null)
            e.setTimeToIdle(tti);
        cache.put(e);
    }

    /**
     * 获得缓存的基本对象列表
     *
     * @param pattern 字符串前缀
     * @return 对象列表
     */
    public static Collection<String> keys(String cacheName, String pattern)
    {
        Cache cache = getCache(cacheName);
        Collection<String> allKeys = cache.getKeys();
        Collection<String> returnkeys = new ArrayList<>();
        for(String key : allKeys){
            if(key.matches(pattern)){
                returnkeys.add(key);
            }
        }
        return returnkeys;
    }

    /**
     * @Description:    删除缓存记录
     * @param cacheName 缓存名字
     * @param key       缓存key
     * @return boolean  是否成功删除
     */
    public static boolean remove(String cacheName, String key) {
        Cache cache = getCache(cacheName);
        if (null == cache) {
            return false;
        }
        return cache.remove(key);
    }

    /**
     * @Description: 删除全部缓存记录
     * @param cacheName 缓存名字
     */
    public static void removeAll(String cacheName) {
        Cache cache = getCache(cacheName);
        if (null != cache) {
            //logOnRemoveAllIfPinnedCache();
            cache.removeAll();
        }
    }

}

第四步:使用缓存

创建缓存:

EhCacheUtil.put(Constants.EHCACHE_NAME, userKey, loginUser, expireTime*60,null);

获取缓存:

EhCacheUtil.get(Constants.EHCACHE_NAME,userKey);

删除缓存:

EhCacheUtil.remove(Constants.EHCACHE_NAME,userKey);

关于SpringBoot连接MSSQL的一些问题

情况1:没有开启TCP/IP连接

com.microsoft.sqlserver.jdbc.SQLServerException: 通过端口 1433 连接到主机 localhost 的 TCP/IP 连接失败。错误:“Socket operation on nonsocket: configureBlocking。请验证连接属性。确保 SQL Server 的实例正在主机上运行,且在此端口接受 TCP/IP 连接,还要确保防火墙没有阻止到此端口的 TCP 连接。”。
	at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:237)
	at com.microsoft.sqlserver.jdbc.SQLServerException.ConvertConnectExceptionToSQLServerException(SQLServerException.java:288)
	at com.microsoft.sqlserver.jdbc.SocketFinder.findSocket(IOBuffer.java:2720)
	at com.microsoft.sqlserver.jdbc.TDSChannel.open(IOBuffer.java:761)
.....

解决方法:

搜索SQL SERVER 配置管理器,启用如下图所示的地方即可:

注意:修改后要重启SQL SERVER服务才能生效。

情况二:安全连接不通过

com.microsoft.sqlserver.jdbc.SQLServerException: 驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。错误:“sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target”。 ClientConnectionId:cae7aed5-1127-4c7e-a992-e9f2a379fd94
	at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:3680)
	at com.microsoft.sqlserver.jdbc.TDSChannel.enableSSL(IOBuffer.java:2113)
	at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectHelper(SQLServerConnection.java:3204)
	at com.microsoft.sqlserver.jdbc.SQLServerConnection.login(SQLServerConnection.java:2833)
	at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectInternal(SQLServerConnection.java:2671)
	at com.microsoft.sqlserver.jdbc.SQLServerConnection.connect(SQLServerConnection.java:1640)
......

解决方法:

原来的连接url是这样写的:

url: jdbc:sqlserver://localhost:1433;DatabaseName=csr-vwork

需要改成以下两种之一:

                url: jdbc:sqlserver://localhost:1433;DatabaseName=csr-vwork;encrypt=false
                url: jdbc:sqlserver://localhost:1433;DatabaseName=csr-vwork;encrypt=true;trustServerCertificate=true

这个是因为sqlever在jdbc连接的时候需要一定的安全验证,我们跳过或者强制可信即可。

close