先添加Jedis依赖
测试是否连接成功
public static void main(String[] args) {
//1、创建Jedis对象
Jedis jedis=new Jedis("192.168.111.130",6379);//前面个是连接的主机ip,后面个是redis的端口号
//2、测试
String ping=jedis.ping();
//成功返回PONG
System.out.println(ping);
}
如果未成功之前写的配置文件有讲,修改即可。
使用示例
/**
* 操作 String
*/
@Test
public void testString(){
Jedis jedis=new Jedis("192.168.111.130",6379);//前面个是连接的主机ip,后面个是redis的端口号
jedis.set("name","lisi");//添加
System.out.println(jedis.get("name"));//取值
jedis.mset("school","cqupt","position","nanshan");//一次添加多个
System.out.println("======================================");
Set<String> set=jedis.keys("*");//查看所有的key
for (String x:set)
System.out.println(x);
}
/**
* 操作 list
*/
@Test
public void testList(){
Jedis jedis=new Jedis("192.168.111.130",6379);//前面个是连接的主机ip,后面个是redis的端口号
jedis.lpush("name","zhangsan","lisi","wangwu");//list添加
System.out.println("======================================");
List<String> set=jedis.lrange("name",0,-1);//取出name中所value
for (String key:set)
System.out.println(key);
}
/**
* 操作 Set
*/
@Test
public void testSet(){
Jedis jedis=new Jedis("192.168.111.130",6379);//前面个是连接的主机ip,后面个是redis的端口号
jedis.sadd("school","qupt","cqust");
System.out.println("======================================");
Set<String> set=jedis.smembers("school");
for (String key:set)
System.out.println(key);
}
/**
* 操作 Hash
*/
@Test
public void testHash(){
Jedis jedis=new Jedis("192.168.111.130",6379);//前面个是连接的主机ip,后面个是redis的端口号
Map<String,String> map=new HashMap<String, String>();
map.put("java","200");
map.put("c++","250");
jedis.hset("programmer",map);
System.out.println("======================================");
String set=jedis.hget("programmer","c++");
System.out.println(set);
}
/**
* 操作 Zset
*/
@Test
public void testZset(){
Jedis jedis=new Jedis("192.168.111.130",6379);//前面个是连接的主机ip,后面个是redis的端口号
jedis.zadd("brand",2,"绿豆");
jedis.zadd("brand",5,"可爱多");
System.out.println("======================================");
Set<String> set=jedis.zrange("brand",0,1);
for (String key:set)
System.out.println(key);
}
手机验证码功能
1、输入手机号,点击发送后随机生成6位数字码,2分钟有效
2、输入验证码,点击验证,返回成功或者失败
3、每个手机号每天只能输入三次
这里
整合Spring-boot
1、添加依赖
<!-- redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
2、yaml配置文件
我用的是jedis所以选了下type
spring:
redis:
host: 192.168.111.130
client-type: jedis
port: 6379
3、网页测试
成功显示。
@RestController
@RequestMapping("/user")
public class testRedis {
@Autowired
private RedisTemplate redisTemplate;
@GetMapping("hello")
public String testRedis() {
//设置值到redis
redisTemplate.opsForValue().set("name","syf");
//从redis获取值
String name = (String)redisTemplate.opsForValue().get("name");
return name;
}
}
Redis连接池
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* 连接池
*/
public class JedisPoolUtil {
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(200);//最大连接数
poolConfig.setMaxIdle(32);//空闲时间
poolConfig.setMaxWaitMillis(100*1000);//最大等待时间
poolConfig.setBlockWhenExhausted(true);
poolConfig.setTestOnBorrow(true); //测试连接 ping PONG
//基本配置 ip redis端口号 连接超时时间
jedisPool = new JedisPool(poolConfig, "192.168.111.130", 6379, 60000 );
}
}
}
return jedisPool;
}
public static void release(JedisPool jedisPool, Jedis jedis) {
if (null != jedis) {
jedisPool.returnResource(jedis);
}
}
}
设置主从复制连接池
private static JedisSentinelPool jedisSentinelPool=null;
public static Jedis getJedisFromSentinel(){
if(jedisSentinelPool==null){
Set<String> sentinelSet=new HashSet<>();
sentinelSet.add("192.168.111.130:26379");//26379为哨兵模式开启后的端口号,192.168.111.130为Linux的ip
jedisPoolConfig =new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(10); //最大可用连接数
jedisPoolConfig.setMaxIdle(5); //最大闲置连接数
jedisPoolConfig.setMinIdle(5); //最小闲置连接数
jedisPoolConfig.setBlockWhenExhausted(true); //连接耗尽是否等待
jedisPoolConfig.setMaxWaitMillis(2000); //等待时间
jedisPoolConfig.setTestOnBorrow(true); //取连接的时候进行一下测试 ping pong
jedisSentinelPool=new JedisSentinelPool("mymaster",sentinelSet,jedisPoolConfig);//mymaster为对监控主机的外号
return jedisSentinelPool.getResource();
}else{
return jedisSentinelPool.getResource();
}
}
集群的Jedis开发
/**
* Redis集群
*/
public class RedisCluster {
public static void main(String[] args) {
//相当于redis-cli -c -p 6379连接集群
HostAndPort hostAndPort = new HostAndPort("192.168.111.130", 6379);//端口号填任意一个都行,因为它可以自动切换
//这三行也行,两种方法
// Set<HostAndPort> set=new HashSet<>();
// set.add(hostAndPort);
// JedisCluster jedisCluster=new JedisCluster(set);
//创建JedisCluster对象
JedisCluster jedisCluster=new JedisCluster(hostAndPort);
//操作
jedisCluster.set("o","value");
String value=jedisCluster.get("b1");
System.out.println("value:"+value);
}
}
分布式锁
UUID防误删锁
public void testLock(){
//生成一个锁的id
String uuid = UUID.randomUUID().toString();
//1获取锁,setIfAbsent相当于setne
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid,3, TimeUnit.SECONDS);//3为时间 TimeUnit.SECONDS为时间单位
//2获取锁成功、查询num的值
if(lock){
Object value = redisTemplate.opsForValue().get("num");
//2.1判断num为空return
if(StringUtils.isEmpty(value)){
return;
}
//2.2有值就转成成int
int num = Integer.parseInt(value+"");
//2.3把redis的num加1
redisTemplate.opsForValue().set("num", ++num);
//2.4释放锁,del
//判断比较uuid值是否一样
String lockUuid = (String)redisTemplate.opsForValue().get("lock");
if(null!=lockUuid&&lockUuid.equals(uuid)) {
redisTemplate.delete("lock");
}
}else{
//3获取锁失败、每隔0.1秒再获取
try {
Thread.sleep(100);
testLock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
LUA脚本保证删除的原子性
public void testLockLua() {
//1 声明一个uuid ,将做为一个value 放入我们的key所对应的值中
String uuid = UUID.randomUUID().toString();
//2 定义一个锁:lua 脚本可以使用同一把锁,来实现删除!
String skuId = "25"; // 访问skuId 为25号的商品 100008348542
String locKey = "lock:" + skuId; // 锁住的是每个商品的数据
// 3 获取锁
Boolean lock = redisTemplate.opsForValue().setIfAbsent(locKey, uuid, 3, TimeUnit.SECONDS);
// 第一种: lock 与过期时间中间不写任何的代码。
// redisTemplate.expire("lock",10, TimeUnit.SECONDS);//设置过期时间
// 如果true
if (lock) {
// 执行的业务逻辑开始
// 获取缓存中的num 数据
Object value = redisTemplate.opsForValue().get("num");
// 如果是空直接返回
if (StringUtils.isEmpty(value)) {
return;
}
// 不是空 如果说在这出现了异常! 那么delete 就删除失败! 也就是说锁永远存在!
int num = Integer.parseInt(value + "");
// 使num 每次+1 放入缓存
redisTemplate.opsForValue().set("num", String.valueOf(++num));
/*使用lua脚本来锁*/
// 定义lua 脚本
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
// 使用redis执行lua执行
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
redisScript.setScriptText(script);
// 设置一下返回值类型 为Long
// 因为删除判断的时候,返回的0,给其封装为数据类型。如果不封装那么默认返回String 类型,
// 那么返回字符串与0 会有发生错误。
redisScript.setResultType(Long.class);
// 第一个要是script 脚本 ,第二个需要判断的key,第三个就是key所对应的值。
redisTemplate.execute(redisScript, Arrays.asList(locKey), uuid);
} else {
// 其他线程等待
try {
// 睡眠
Thread.sleep(1000);
// 睡醒了之后,调用方法。
testLockLua();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}