SpringBoot(十四):SpringBoot整合Memcached


一、環境准備

  • memcached 1.4.5
  • SpringBoot 1.5.10.RELEASE
  • java_memcached-release_2.6.6.jar

memcached 1.4.5 windows 下載地址:http://www.runoob.com/memcached/window-install-memcached.html

danga memcached java client 下載地址:https://github.com/gwhalin/Memcached-Java-Client/downloads

pom依賴:

        <dependency>
            <groupId>commons-pool</groupId>
            <artifactId>commons-pool</artifactId>
            <version>1.5.6</version>
        </dependency>

        <dependency>
            <groupId>com.danga</groupId>
            <artifactId>java_memcached-release</artifactId>
            <version>2.6.6</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/java_memcached-release_2.6.6.jar</systemPath>
        </dependency>

二、項目結構

這里寫圖片描述

三、代碼詳情

application.yml

## Memcache 配置 ##
memcache:
  servers: 127.0.0.1:11211
  failover: true
  initConn: 100
  minConn: 20
  maxConn: 1000
  maintSleep: 50
  nagel: false
  socketTO: 3000
  aliveCheck: true

MemcacheConfiguration.java

package cn.saytime.config;

import com.danga.MemCached.MemCachedClient;
import com.danga.MemCached.SockIOPool;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/** * @author zh * @ClassName cn.saytime.config.config.MemcacheConfiguration * @Description Memcache配置 */
@Configuration
public class MemcacheConfiguration {

    @Value("${memcache.servers}")
    private String[] servers;
    @Value("${memcache.failover}")
    private boolean failover;
    @Value("${memcache.initConn}")
    private int initConn;
    @Value("${memcache.minConn}")
    private int minConn;
    @Value("${memcache.maxConn}")
    private int maxConn;
    @Value("${memcache.maintSleep}")
    private int maintSleep;
    @Value("${memcache.nagel}")
    private boolean nagel;
    @Value("${memcache.socketTO}")
    private int socketTO;
    @Value("${memcache.aliveCheck}")
    private boolean aliveCheck;

    @Bean
    public SockIOPool sockIOPool () {
        SockIOPool pool = SockIOPool.getInstance();
        pool.setServers(servers);
        pool.setFailover(failover);
        pool.setInitConn(initConn);
        pool.setMinConn(minConn);
        pool.setMaxConn(maxConn);
        pool.setMaintSleep(maintSleep);
        pool.setNagle(nagel);
        pool.setSocketTO(socketTO);
        pool.setAliveCheck(aliveCheck);
        pool.initialize();
        return pool;
    }

    @Bean
    public MemCachedClient memCachedClient(){
        return new MemCachedClient();
    }

}

測試類 SpringbootMemcacheApplicationTests.java

package cn.saytime;

import com.danga.MemCached.MemCachedClient;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Date;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootMemcacheApplicationTests {

    @Autowired
    private MemCachedClient memCachedClient;

    @Test
    public void contextLoads() throws InterruptedException {
        // 放入緩存
        boolean flag = memCachedClient.set("a", 1);

        // 取出緩存
        Object a = memCachedClient.get("a");
        System.out.println(a);


        // 3s后過期
        memCachedClient.set("b", "2", new Date(3000));
        Object b = memCachedClient.get("b");
        System.out.println(b);

        Thread.sleep(3000);
        b = memCachedClient.get("b");
        System.out.println(b);

    }

}

先運行memcached,然后執行test,輸出結果為:

1
2
null

測試memcached存取以及失效時間成功。

四、部分操作方法

  1. set與add在key不存在時效果一致,add在key存在時不會成功。
  2. set與replace在key存在時效果一致,replace在key不存在不會成功。

五、注意點

使用danga memcached設置失效時間有兩種方式:

  1. 第一種
memCachedClient.set("xx", "xx", new Date(3000));
  1. 第二種
memCachedClient.set("xx", "xx", new Date(System.currentTimeMillis() + 3 * 1000));

對比兩種形式,第一種是指定key在3s后過期,第二種是指定key在xxxx-xx-xx xx:xx:xx 時間點失效,如果服務器時間跟客戶端時間不一致,就會跟想要的結果不一樣,比如客戶端現在時間點為2018-01-01 00:00:00,服務端時間為2018-01-01 00:00:10,服務端時間快10s,那么如果客戶端使用第二種方式設置30s后失效,也就是2018-01-01 00:00:30失效,實際上客戶端想要的是30s后失效,而服務端20s就將key失效了。

從上可以發現,最好是使用第一種形式,但是第一種形式在某些時間也會存在問題,比如如果設定的時間小於1s,會發現key會永久保存,不會在指定時間失效,原因可以通過源碼得到。

我們使用的MemCachedClient,在configuration里面是直接new的,也就是

new MemCachedClient();

查看MemCachedClient的set帶時間方法,可以看到:

    public boolean set(String var1, Object var2, Date var3) {
        return this.client.set(var1, var2, var3);
    }

而這個client是在構造方法實例化的,也就是

    public MemCachedClient() {
        this((String)null, true, false);
    }

    public MemCachedClient(String var1, boolean var2, boolean var3) {
        this.BLAND_DATA_SIZE = " ".getBytes();
        if(var3) {
            this.client = new BinaryClient(var1);
        } else {
            this.client = (MemCachedClient)(var2?new AscIIClient(var1):new AscIIUDPClient(var1));
        }

    }

可以看到實際上執行類是AscIIClient,接下來我們查看AscIIClient的帶失效時間的set方法

    public boolean set(String var1, Object var2, Date var3) {
        return this.set("set", var1, var2, var3, (Integer)null, Long.valueOf(0L), this.primitiveAsString);
    }

    private boolean set(String var1, String var2, Object var3, Date var4, Integer var5, Long var6, boolean var7) {

        // xxx

        // 這里的var4就是傳入的失效時間
        String var10 = var1 + " " + var2 + " " + var9 + " " + var4.getTime() / 1000L + " ";

        // xxx
    }

可以看到這里有執行

var4.getTime() / 1000L

也就是在var.getTime()小於1的時候,得到的結果是0,而0表示永久有效。

我們來測試一下,在代碼中加入以下代碼

        memCachedClient.set("c", "3", new Date(500));
        Object c = memCachedClient.get("c");
        System.out.println(c);

        Thread.sleep(1000);
        c = memCachedClient.get("c");
        System.out.println(c);

設置時間為0.5s,然后立馬取出結果,然后等待1s之后,再次取出結果.

通過上面的說明,結果可想而知。

3
3

說明當時間小於1s的時候,使用第一種方式會造成指定時間不生效,key永久存在,這種時間如果客戶端服務端時間沒有誤差的時候,使用第二種形式。

關於memcached最大設置30天有效的情形暫時沒有測試。


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com