几点理解redis
redis是非关系型数据。
操作redis类似于操作数据库,使用原生的jedis就是每次使用时获取一个连接,然后操作数据,操作完归还或者关闭连接,使用spring框架连接的话可以直接注入xxTemplate对象,使用template的api操作数据库。
redis的基本使用主要是基于redis支持的五种数据类型,根据不同的数据结构特性结合实际业务需求来实现不同的业务场景。
redis高级使用就是分布式事务,分布式锁;目前尚在学习探索…
如何操作redis
主流集成redis的方式:
- 集成官方推荐的jedis
- 进一步封装jedis的redisson
- spring框架自带的redisTemplate
Jedis和Redisson都是JAVA对redis操作的封装。jedis只是简单的封装了redis的api库,可以看做是jedis的客户端, 它的方法和redis的命令相似。Redisson不仅封装了redis,还封装了对更多数据结构的支持,以及锁等功能,总得来说二者之间Redisson更加丰富更强大,jedis偏原生,更加灵活。
环境搭建
新创建springboot项目
导入start依赖
<!--redis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
jedis集成
Jedis 是Java 实现的Redis 客户端,偏原生,使用主要是使用jedisPool。
## 配置连接池的参数信息
@Configuration
public class JedisConfig {
private JedisPoolConfig jedisPoolConfig;
@Bean
public JedisPoolConfig generateJedisPool(){
this.jedisPoolConfig = new JedisPoolConfig();
//可分配实例数-最大连接数
jedisPoolConfig.setMaxTotal(8);
//最大空闲连接数
jedisPoolConfig.setMaxIdle(8);
//最大等待时间
jedisPoolConfig.setMaxWaitMillis(1000);
return jedisPoolConfig;
}
}
## 创建redis工具类 操作redis (仅做项目结构展示,util中代码可自行忽略)
@Component
public class JedisUtil {
private static final Long RELEASE_SUCCESS = 1L;
private static final String LOCK_SUCCESS = "OK";
private static final String SET_IF_NOT_EXIST = "NX";
private static final String SET_WITH_EXPIRE_TIME = "PX";
private long timeout = 100; //获取锁的超时时间
@Value("${spring.redis.database}")
private int databaseIndex;
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.commandTimeout}")
private int redisTimeout;
@Autowired
private JedisConfig poolConfig;
private volatile JedisPool jedisPool = null;
//构建连接池
//单例 懒汉加载模式
public JedisPool getInstance() {
if (jedisPool == null) {
this.jedisPool = new JedisPool(poolConfig.generateJedisPool(),
this.host, this.port, this.redisTimeout, this.password, this.databaseIndex
);
return jedisPool;
}
return this.jedisPool;
}
/**
* 尝试获取分布式锁
*
* @param lockKey 锁
* @param requestId 请求标识 (可用于避免消息重复消费)
* @param expireTime 超时时间 (宕机导致无法释放锁)
* @return
*/
public boolean tryGetDistributedLock(String lockKey,
String requestId,
int expireTime) {
JedisPool pool = getInstance();
Jedis jedis = null;
long start = System.currentTimeMillis();
try {
jedis = pool.getResource();
while (true) {
//nx 仅在键不存在时 设置键
String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST);
if (LOCK_SUCCESS.equals(result)) {
return true;
} else {
//则循环等待 在timeout时间内仍未获取到锁 则获取失败
long waitTime = System.currentTimeMillis() - start;
if (waitTime >= timeout) {
return false;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} catch (Exception e) {
//异常 直接关闭连接池
pool.close();
e.printStackTrace();
return false;
} finally {
//返还到连接池
returnResource(pool, jedis);
}
}
/**
* 释放分布式锁
* @param lockKey 锁
* @param requestId 请求标识
* @return
*/
public boolean releaseDistributedLock(String lockKey , String requestId){
if (StringUtils.isEmpty(lockKey) || StringUtils.isEmpty(requestId)) {
return true;
}
JedisPool pool = getInstance();
Jedis jedis = null;
try {
jedis = pool.getResource();//每次操作时向pool借用个jedis对象,用完即还
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
if (RELEASE_SUCCESS.equals(result)) {
return true;
} else {
return false;
}
} catch (Exception e) {
pool.returnBrokenResource(jedis);
e.printStackTrace();
return false;
} finally {
returnResource(pool, jedis);
}
}
private void returnResource(JedisPool pool, Jedis jedis) {
if (jedis != null) {
pool.returnResource(jedis);
}
}
}
spring的redisTemplate
## 使用方式简单粗暴,直接注入template即可使用Java代码操作数据库,
实际使用再封装一层util方便项目中调用即可
@Component
public class RedisUtil {
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* 存放string类型
*
* @param key
* key
* @param data
* 数据
* @param timeout
* 超时间
*/
public void setString(String key, String data, Long timeout) {
try {
stringRedisTemplate.opsForValue().set(key, data);
if (timeout != null) {
stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
}
} catch (Exception e) {
}
}
/**
* 开启Redis 事务
*
*/
public void begin() {
// 开启Redis 事务权限
stringRedisTemplate.setEnableTransactionSupport(true);
// 开启事务
stringRedisTemplate.multi();
}