介绍一下redis_redis sortedset

介绍一下redis_redis sortedset想要操作redis,就需要与redis建立连接。就像操作MySQL一样,需要首先拿到数据库链接。进而,类似于MySQL的DataSource,ActiveMQ的pool,redis也提供了自己的pool–JedisPool。这些”池”理念是相通的,把你从繁琐的手动获取释放链接解放出来,减少了资源消耗,提高了性能。【1】先看源码源码如下:packageredis.clien…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

想要操作redis,就需要与redis建立连接。就像操作MySQL一样,需要首先拿到数据库链接。

进而,类似于MySQL的DataSource,ActiveMQ的pool,redis也提供了自己的pool–JedisPool。这些”池”理念是相通的,把你从繁琐的手动获取释放链接解放出来,减少了资源消耗,提高了性能。

【1】先看源码

源码如下:

package redis.clients.jedis;
import java.net.URI;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocketFactory;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.exceptions.JedisException;
import redis.clients.util.JedisURIHelper;
import redis.clients.util.Pool;
public class JedisPool extends Pool<Jedis> { 

public JedisPool() {
this(Protocol.DEFAULT_HOST, Protocol.DEFAULT_PORT);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final String host) {
this(poolConfig, host, Protocol.DEFAULT_PORT, Protocol.DEFAULT_TIMEOUT, null,
Protocol.DEFAULT_DATABASE, null);
}
public JedisPool(String host, int port) {
this(new GenericObjectPoolConfig(), host, port, Protocol.DEFAULT_TIMEOUT, null,
Protocol.DEFAULT_DATABASE, null);
}
public JedisPool(final String host) {
URI uri = URI.create(host);
if (JedisURIHelper.isValid(uri)) {
String h = uri.getHost();
int port = uri.getPort();
String password = JedisURIHelper.getPassword(uri);
int database = JedisURIHelper.getDBIndex(uri);
boolean ssl = uri.getScheme().equals("rediss");
this.internalPool = new GenericObjectPool<Jedis>(new JedisFactory(h, port,
Protocol.DEFAULT_TIMEOUT, Protocol.DEFAULT_TIMEOUT, password, database, null,
ssl, null, null, null), new GenericObjectPoolConfig());
} else {
this.internalPool = new GenericObjectPool<Jedis>(new JedisFactory(host,
Protocol.DEFAULT_PORT, Protocol.DEFAULT_TIMEOUT, Protocol.DEFAULT_TIMEOUT, null,
Protocol.DEFAULT_DATABASE, null, false, null, null, null), new GenericObjectPoolConfig());
}
}
public JedisPool(final String host, final SSLSocketFactory sslSocketFactory,
final SSLParameters sslParameters, final HostnameVerifier hostnameVerifier) {
URI uri = URI.create(host);
if (JedisURIHelper.isValid(uri)) {
String h = uri.getHost();
int port = uri.getPort();
String password = JedisURIHelper.getPassword(uri);
int database = JedisURIHelper.getDBIndex(uri);
boolean ssl = uri.getScheme().equals("rediss");
this.internalPool = new GenericObjectPool<Jedis>(new JedisFactory(h, port,
Protocol.DEFAULT_TIMEOUT, Protocol.DEFAULT_TIMEOUT, password, database, null, ssl,
sslSocketFactory, sslParameters, hostnameVerifier),
new GenericObjectPoolConfig());
} else {
this.internalPool = new GenericObjectPool<Jedis>(new JedisFactory(host,
Protocol.DEFAULT_PORT, Protocol.DEFAULT_TIMEOUT, Protocol.DEFAULT_TIMEOUT, null,
Protocol.DEFAULT_DATABASE, null, false, null, null, null), new GenericObjectPoolConfig());
}
}
public JedisPool(final URI uri) {
this(new GenericObjectPoolConfig(), uri, Protocol.DEFAULT_TIMEOUT);
}
public JedisPool(final URI uri, final SSLSocketFactory sslSocketFactory,
final SSLParameters sslParameters, final HostnameVerifier hostnameVerifier) {
this(new GenericObjectPoolConfig(), uri, Protocol.DEFAULT_TIMEOUT, sslSocketFactory,
sslParameters, hostnameVerifier);
}
public JedisPool(final URI uri, final int timeout) {
this(new GenericObjectPoolConfig(), uri, timeout);
}
public JedisPool(final URI uri, final int timeout, final SSLSocketFactory sslSocketFactory,
final SSLParameters sslParameters, final HostnameVerifier hostnameVerifier) {
this(new GenericObjectPoolConfig(), uri, timeout, sslSocketFactory, sslParameters,
hostnameVerifier);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, int port,
int timeout, final String password) {
this(poolConfig, host, port, timeout, password, Protocol.DEFAULT_DATABASE, null);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, int port,
int timeout, final String password, final boolean ssl) {
this(poolConfig, host, port, timeout, password, Protocol.DEFAULT_DATABASE, null, ssl);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, int port,
int timeout, final String password, final boolean ssl,
final SSLSocketFactory sslSocketFactory, final SSLParameters sslParameters,
final HostnameVerifier hostnameVerifier) {
this(poolConfig, host, port, timeout, password, Protocol.DEFAULT_DATABASE, null, ssl,
sslSocketFactory, sslParameters, hostnameVerifier);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, final int port) {
this(poolConfig, host, port, Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE, null);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, final int port,
final boolean ssl) {
this(poolConfig, host, port, Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE, null,
ssl);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, final int port,
final boolean ssl, final SSLSocketFactory sslSocketFactory, final SSLParameters sslParameters,
final HostnameVerifier hostnameVerifier) {
this(poolConfig, host, port, Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE, null,
ssl, sslSocketFactory, sslParameters, hostnameVerifier);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, final int port,
final int timeout) {
this(poolConfig, host, port, timeout, null, Protocol.DEFAULT_DATABASE, null);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, final int port,
final int timeout, final boolean ssl) {
this(poolConfig, host, port, timeout, null, Protocol.DEFAULT_DATABASE, null, ssl);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, final int port,
final int timeout, final boolean ssl, final SSLSocketFactory sslSocketFactory,
final SSLParameters sslParameters, final HostnameVerifier hostnameVerifier) {
this(poolConfig, host, port, timeout, null, Protocol.DEFAULT_DATABASE, null, ssl,
sslSocketFactory, sslParameters, hostnameVerifier);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, int port,
int timeout, final String password, final int database) {
this(poolConfig, host, port, timeout, password, database, null);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, int port,
int timeout, final String password, final int database, final boolean ssl) {
this(poolConfig, host, port, timeout, password, database, null, ssl);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, int port,
int timeout, final String password, final int database, final boolean ssl,
final SSLSocketFactory sslSocketFactory, final SSLParameters sslParameters,
final HostnameVerifier hostnameVerifier) {
this(poolConfig, host, port, timeout, password, database, null, ssl, sslSocketFactory,
sslParameters, hostnameVerifier);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, int port,
int timeout, final String password, final int database, final String clientName) {
this(poolConfig, host, port, timeout, timeout, password, database, clientName, false,
null, null, null);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, int port,
int timeout, final String password, final int database, final String clientName,
final boolean ssl) {
this(poolConfig, host, port, timeout, timeout, password, database, clientName, ssl,
null, null, null);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, int port,
int timeout, final String password, final int database, final String clientName,
final boolean ssl, final SSLSocketFactory sslSocketFactory,
final SSLParameters sslParameters, final HostnameVerifier hostnameVerifier) {
this(poolConfig, host, port, timeout, timeout, password, database, clientName, ssl,
sslSocketFactory, sslParameters, hostnameVerifier);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, int port,
final int connectionTimeout, final int soTimeout, final String password, final int database,
final String clientName, final boolean ssl, final SSLSocketFactory sslSocketFactory,
final SSLParameters sslParameters, final HostnameVerifier hostnameVerifier) {
super(poolConfig, new JedisFactory(host, port, connectionTimeout, soTimeout, password,
database, clientName, ssl, sslSocketFactory, sslParameters, hostnameVerifier));
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final URI uri) {
this(poolConfig, uri, Protocol.DEFAULT_TIMEOUT);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final URI uri,
final SSLSocketFactory sslSocketFactory, final SSLParameters sslParameters,
final HostnameVerifier hostnameVerifier) {
this(poolConfig, uri, Protocol.DEFAULT_TIMEOUT, sslSocketFactory, sslParameters,
hostnameVerifier);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final URI uri, final int timeout) {
this(poolConfig, uri, timeout, timeout);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final URI uri, final int timeout,
final SSLSocketFactory sslSocketFactory, final SSLParameters sslParameters,
final HostnameVerifier hostnameVerifier) {
this(poolConfig, uri, timeout, timeout, sslSocketFactory, sslParameters, hostnameVerifier);
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final URI uri,
final int connectionTimeout, final int soTimeout) {
super(poolConfig, new JedisFactory(uri, connectionTimeout, soTimeout, null, false,
null, null, null));
}
public JedisPool(final GenericObjectPoolConfig poolConfig, final URI uri,
final int connectionTimeout, final int soTimeout, final SSLSocketFactory sslSocketFactory,
final SSLParameters sslParameters, final HostnameVerifier hostnameVerifier) {
super(poolConfig, new JedisFactory(uri, connectionTimeout, soTimeout, null,
(uri.getScheme() !=null && uri.getScheme().equals("rediss")), sslSocketFactory,
sslParameters, hostnameVerifier));
}
// 从池子中拿到jedis实例
@Override
public Jedis getResource() {
Jedis jedis = super.getResource();
jedis.setDataSource(this);
return jedis;
}
// 归还链接,将jedis实例归还给池子
/** * @deprecated starting from Jedis 3.0 this method will not be exposed. Resource cleanup should be * done using @see {@link redis.clients.jedis.Jedis#close()} */
@Override
@Deprecated
public void returnBrokenResource(final Jedis resource) {
if (resource != null) {
returnBrokenResourceObject(resource);
}
}
/** * @deprecated starting from Jedis 3.0 this method will not be exposed. Resource cleanup should be * done using @see {@link redis.clients.jedis.Jedis#close()} */
@Override
@Deprecated
public void returnResource(final Jedis resource) {
if (resource != null) {
try {
resource.resetState();
returnResourceObject(resource);
} catch (Exception e) {
returnBrokenResource(resource);
throw new JedisException("Could not return the resource to the pool", e);
}
}
}
}

总得来说有三点,JedisPool各种构造方法,提供了获取jedis实例的方法以及释放资源(归还实例)的方法。不过第三点,已经过时建议使用Jedis.close()。


【2】初始化JedisPool

想要使用JedisPool获取Jedis操作redis,首先需要将JedisPool初始化。

JedisPool初始化一定是唯一的,也就是说需要使用单例模式。

这里使用双重校验锁初始化JedisPool:

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class JedisPoolUtil { 

// 注意之类使用volatile 关键字
private static volatile JedisPool jedisPool = null;
private JedisPoolUtil(){}
public static JedisPool getJedisPoolInstance()
{
if(null == jedisPool)
{
//双重校验锁
synchronized (JedisPoolUtil.class)
{
if(null == jedisPool)
{
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(1000);
poolConfig.setMaxIdle(32);
poolConfig.setTestOnBorrow(true);
//...其他配置
jedisPool = new JedisPool(poolConfig,"127.0.0.1",6379);
}
}
}
return jedisPool;
}
/** * 获取Jedis实例 * * @return */
public synchronized static Jedis getJedis() {
try {
if (jedisPool != null) {
Jedis jedis = jedisPool.getResource();
return jedis;
} else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/** * 释放资源 * @param jedis */
public static void release(Jedis jedis)
{
if(null != jedis)
{
jedis.close();
}
}
}

项目中常常会在容器动的时候就初始化好各种池,故而可在容器启动的时候就初始化JedisPool将其放到容器中。

常见两种方式:XML配置或者在SpringBoot下使用@Bean注入。


【3】JedisPoolConfig

如上,我们看到池子初始化可以设置诸多属性。

JedisPoolConfig 源码如下:

public class JedisPoolConfig extends GenericObjectPoolConfig { 

public JedisPoolConfig() {
// defaults to make your life with connection pool easier :)
setTestWhileIdle(true);
setMinEvictableIdleTimeMillis(60000);
setTimeBetweenEvictionRunsMillis(30000);
setNumTestsPerEvictionRun(-1);
}
}

其父类GenericObjectPoolConfig 中属性如下:

public class GenericObjectPoolConfig extends BaseObjectPoolConfig { 

/** * The default value for the {@code maxTotal} configuration attribute. * @see GenericObjectPool#getMaxTotal() */
public static final int DEFAULT_MAX_TOTAL = 8;
/** * The default value for the {@code maxIdle} configuration attribute. * @see GenericObjectPool#getMaxIdle() */
public static final int DEFAULT_MAX_IDLE = 8;
/** * The default value for the {@code minIdle} configuration attribute. * @see GenericObjectPool#getMinIdle() */
public static final int DEFAULT_MIN_IDLE = 0;
private int maxTotal = DEFAULT_MAX_TOTAL;
private int maxIdle = DEFAULT_MAX_IDLE;
private int minIdle = DEFAULT_MIN_IDLE;
//...
}

其父类BaseObjectPoolConfig中属性如下:

public abstract class BaseObjectPoolConfig implements Cloneable { 

/** * The default value for the {@code lifo} configuration attribute. * @see GenericObjectPool#getLifo() * @see GenericKeyedObjectPool#getLifo() */
public static final boolean DEFAULT_LIFO = true;
/** * The default value for the {@code fairness} configuration attribute. * @see GenericObjectPool#getFairness() * @see GenericKeyedObjectPool#getFairness() */
public static final boolean DEFAULT_FAIRNESS = false;
/** * The default value for the {@code maxWait} configuration attribute. * @see GenericObjectPool#getMaxWaitMillis() * @see GenericKeyedObjectPool#getMaxWaitMillis() */
public static final long DEFAULT_MAX_WAIT_MILLIS = -1L;
/** * The default value for the {@code minEvictableIdleTimeMillis} * configuration attribute. * @see GenericObjectPool#getMinEvictableIdleTimeMillis() * @see GenericKeyedObjectPool#getMinEvictableIdleTimeMillis() */
public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS =
1000L * 60L * 30L;
/** * The default value for the {@code softMinEvictableIdleTimeMillis} * configuration attribute. * @see GenericObjectPool#getSoftMinEvictableIdleTimeMillis() * @see GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis() */
public static final long DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS = -1;
/** * The default value for the {@code numTestsPerEvictionRun} configuration * attribute. * @see GenericObjectPool#getNumTestsPerEvictionRun() * @see GenericKeyedObjectPool#getNumTestsPerEvictionRun() */
public static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3;
/** * The default value for the {@code testOnCreate} configuration attribute. * @see GenericObjectPool#getTestOnCreate() * @see GenericKeyedObjectPool#getTestOnCreate() * * @since 2.2 */
public static final boolean DEFAULT_TEST_ON_CREATE = false;
/** * The default value for the {@code testOnBorrow} configuration attribute. * @see GenericObjectPool#getTestOnBorrow() * @see GenericKeyedObjectPool#getTestOnBorrow() */
public static final boolean DEFAULT_TEST_ON_BORROW = false;
/** * The default value for the {@code testOnReturn} configuration attribute. * @see GenericObjectPool#getTestOnReturn() * @see GenericKeyedObjectPool#getTestOnReturn() */
public static final boolean DEFAULT_TEST_ON_RETURN = false;
/** * The default value for the {@code testWhileIdle} configuration attribute. * @see GenericObjectPool#getTestWhileIdle() * @see GenericKeyedObjectPool#getTestWhileIdle() */
public static final boolean DEFAULT_TEST_WHILE_IDLE = false;
/** * The default value for the {@code timeBetweenEvictionRunsMillis} * configuration attribute. * @see GenericObjectPool#getTimeBetweenEvictionRunsMillis() * @see GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis() */
public static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = -1L;
/** * The default value for the {@code blockWhenExhausted} configuration * attribute. * @see GenericObjectPool#getBlockWhenExhausted() * @see GenericKeyedObjectPool#getBlockWhenExhausted() */
public static final boolean DEFAULT_BLOCK_WHEN_EXHAUSTED = true;
/** * The default value for enabling JMX for pools created with a configuration * instance. */
public static final boolean DEFAULT_JMX_ENABLE = true;
/** * The default value for the prefix used to name JMX enabled pools created * with a configuration instance. * @see GenericObjectPool#getJmxName() * @see GenericKeyedObjectPool#getJmxName() */
public static final String DEFAULT_JMX_NAME_PREFIX = "pool";
/** * The default value for the base name to use to name JMX enabled pools * created with a configuration instance. The default is <code>null</code> * which means the pool will provide the base name to use. * @see GenericObjectPool#getJmxName() * @see GenericKeyedObjectPool#getJmxName() */
public static final String DEFAULT_JMX_NAME_BASE = null;
/** * The default value for the {@code evictionPolicyClassName} configuration * attribute. * @see GenericObjectPool#getEvictionPolicyClassName() * @see GenericKeyedObjectPool#getEvictionPolicyClassName() */
public static final String DEFAULT_EVICTION_POLICY_CLASS_NAME =
"org.apache.commons.pool2.impl.DefaultEvictionPolicy";
private boolean lifo = DEFAULT_LIFO;
private boolean fairness = DEFAULT_FAIRNESS;
// 默认值-1L
private long maxWaitMillis = DEFAULT_MAX_WAIT_MILLIS;
// 默认值 1000L * 60L * 30L;
private long minEvictableIdleTimeMillis =
DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
//默认值-1
private long softMinEvictableIdleTimeMillis =
DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
// 默认值 3
private int numTestsPerEvictionRun =
DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
//默认值org.apache.commons.pool2.impl.DefaultEvictionPolicy
private String evictionPolicyClassName = DEFAULT_EVICTION_POLICY_CLASS_NAME;
// 默认值 false
private boolean testOnCreate = DEFAULT_TEST_ON_CREATE;
// 默认false
private boolean testOnBorrow = DEFAULT_TEST_ON_BORROW;
// 默认false
private boolean testOnReturn = DEFAULT_TEST_ON_RETURN;
// 默认false
private boolean testWhileIdle = DEFAULT_TEST_WHILE_IDLE;
//默认值 -1L
private long timeBetweenEvictionRunsMillis =
DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
//默认值 true
private boolean blockWhenExhausted = DEFAULT_BLOCK_WHEN_EXHAUSTED;
//默认值 true
private boolean jmxEnabled = DEFAULT_JMX_ENABLE;
//默认值 pool
// TODO Consider changing this to a single property for 3.x
private String jmxNamePrefix = DEFAULT_JMX_NAME_PREFIX;
// 默认值 null
private String jmxNameBase = DEFAULT_JMX_NAME_BASE;
//...
}

① maxTotal

最大连接数, 默认8个。如果赋值为-1,则表示不限制;如果pool已经分配了maxTotal 个jedis实例,则此时pool的状态为exhausted。

② maxIdle

最大空闲连接数, 默认8个。控制一个pool最多有多少个状态为idle(空闲的)的jedis实例。

③ minIdle

最小空闲连接数, 默认0个。


④ maxWaitMillis

表示当borrow(引入)一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛出JedisConnectionException。

⑤ testOnBorrow

在borrow一个jedis实例时,是否提前检查连接可用性(ping())操作;如果为true,则得到的jedis实例均是可用的。默认为false。

⑥ blockWhenExhausted

连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true。

⑦ testOnReturn

在return一个jedis实例时,是否检查连接可用性(ping()),默认为false。


⑧ testWhileIdle

如果为true,表示有一个idle object evitor线程对idle object进行扫描,如果validate失败,此object会被从pool中drop掉。

这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义。

JedisPoolConfig中默认设置为true。


⑨ minEvictableIdleTimeMillis

表示一个对象至少停留在idle状态的最短时间,然后才能被idle object evitor扫描并驱逐。

这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义。

JedisPoolConfig中默认设置为60000。


⑩ timeBetweenEvictionRunsMillis

表示idle object evitor两次扫描之间要sleep的毫秒数.

JedisPoolConfig中默认设置为30000。


(11)NumTestsPerEvictionRun

表示idle object evitor每次扫描的最多的对象数。

JedisPoolConfig中默认设置为-1。

 public JedisPoolConfig() {
// defaults to make your life with connection pool easier :)
setTestWhileIdle(true);
setMinEvictableIdleTimeMillis(60000);
setTimeBetweenEvictionRunsMillis(30000);
setNumTestsPerEvictionRun(-1);
}

(12)softMinEvictableIdleTimeMillis

在minEvictableIdleTimeMillis基础上,加入了至少minIdle个对象已经在pool里面了。

如果为-1,evitor不会根据idle time驱逐任何对象。

如果minEvictableIdleTimeMillis>0,则此项设置无意义,且只有在timeBetweenEvictionRunsMillis大于0时才有意义。


(13)lifo

borrowObject返回对象时,是采用DEFAULT_LIFO(last in first out,即类似cache的最频繁使用队列),如果为False,则表示FIFO队列。

其他整合与使用请参考博文:

SpringBoot2.0整合redis

SpringBoot整合Redis详解

SpringBoot缓存入门与注解使用

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/197016.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号