Jedis:分布:
public static void main(String[] args) throws IOException { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxTotal(20); jedisPoolConfig.setMaxIdle(10); jedisPoolConfig.setMinIdle(5); // timeout,这里既是连接超时又是读写超时,从Jedis 2.8开始有区分connectionTimeout和soTimeout的构造函数 JedisPool jedisPool = new JedisPool(jedisPoolConfig, "192.168.0.60", 6379, 3000, null); Jedis jedis = null; try { //从redis连接池里拿出一个连接执行命令 jedis = jedisPool.getResource(); //******* jedis普通操作示例 ******** /*System.out.println(jedis.set("single1", "zhuge")); System.out.println(jedis.get("single1"));*/ //******* 管道示例 ******** //管道的命令执行方式:cat redis.txt | redis-cli -h 127.0.0.1 -a password - p 6379 --pipe /*Pipeline pl = jedis.pipelined(); for (int i = 0; i < 10; i++) { pl.incr("pipelineKey"); pl.set("zhuge" + i, "zhuge"); } List<Object> results = pl.syncAndReturnAll(); System.out.println(results);*/ //******* lua脚本示例 ******** //模拟一个商品减库存的原子操作 //lua脚本命令执行方式:redis-cli --eval /tmp/test.lua , 10 jedis.set("product_stock_10016", "15"); //初始化商品10016的库存 String script = " local count = redis.call('get', KEYS[1]) " + " local a = tonumber(count) " + " local b = tonumber(ARGV[1]) " + " if a >= b then " + " redis.call('set', KEYS[1], count-b) " + //模拟语法报错回滚操作" bb == 0 " + " return 1 " + " end " + " return 0 "; Object obj = jedis.eval(script, Arrays.asList("product_stock_10016"), Arrays.asList("10")); System.out.println(obj); } catch (Exception e) { e.printStackTrace(); } finally { //注意这里不是关闭连接,在JedisPool模式下,Jedis会被归还给资源池。 if (jedis != null) jedis.close(); } } }
public class JedisSentinelTest { public static void main(String[] args) throws IOException { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(20); config.setMaxIdle(10); config.setMinIdle(5); String masterName = "mymaster"; Set<String> sentinels = new HashSet<String>(); sentinels.add(new HostAndPort("192.168.0.60",26379).toString()); sentinels.add(new HostAndPort("192.168.0.60",26380).toString()); sentinels.add(new HostAndPort("192.168.0.60",26381).toString()); //JedisSentinelPool其实本质跟JedisPool类似,都是与redis主节点建立的连接池 //JedisSentinelPool并不是说与sentinel建立的连接池,而是通过sentinel发现redis主节点并与其建立连接 JedisSentinelPool jedisSentinelPool = new JedisSentinelPool(masterName, sentinels, config, 3000, null); Jedis jedis = null; try { jedis = jedisSentinelPool.getResource(); System.out.println(jedis.set("sentinel666", "zhuge")); System.out.println(jedis.get("sentinel666")); } catch (Exception e) { e.printStackTrace(); } finally { //注意这里不是关闭连接,在JedisPool模式下,Jedis会被归还给资源池。 if (jedis != null) jedis.close(); } } }
CRC 校验:
public class CRC16 { public static void main(String[] args){ String str="name1"; System.out.println(JedisClusterCRC16.getCRC16(str)%16384); } }
二.redis spring boot 集成:
redis 配置文件:
server: port: 8080 spring: redis: database: 0 timeout: 3000 password: zhuge # sentinel: #哨兵模式 # master: mymaster #主服务器所在集群名称 # nodes: 192.168.0.60:26379,192.168.0.60:26380,192.168.0.60:26381 cluster: nodes: 192.168.0.61:8001,192.168.0.62:8002,192.168.0.63:8003,192.168.0.61:8004,192.168.0.62:8005,192.168.0.63:8006 lettuce: pool: max-idle: 50 min-idle: 10 max-active: 100 max-wait: 1000
APPlication:
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
@RestController public class IndexController { private static final Logger logger = LoggerFactory.getLogger(IndexController.class); @Autowired private StringRedisTemplate stringRedisTemplate; /** * 测试节点挂了哨兵重新选举新的master节点,客户端是否能动态感知到 * * @throws InterruptedException */ @RequestMapping("/test_sentinel") public void testSentinel() throws InterruptedException { int i = 1; while (true){ try { stringRedisTemplate.opsForValue().set("zhuge"+i, i+""); //jedis.set(key,value); System.out.println("设置key:"+ "zhuge" + i); i++; Thread.sleep(1000); }catch (Exception e){ logger.error("错误:", e); } } } }
redis 分布式锁:
配置文件:
server: port: 8090 spring: redis: host: 192.168.0.60 port: 6379
分布式锁的方案:
@RestController public class IndexController { private static final Logger logger = LoggerFactory.getLogger(IndexController.class); @Autowired private Redisson redisson; @Autowired private StringRedisTemplate stringRedisTemplate; @RequestMapping("/deduct_stock") public String deductStock() throws InterruptedException { String lockKey = "product_001"; //String clientId = UUID.randomUUID().toString(); RLock redissonLock = redisson.getLock(lockKey); try { //Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "zhuge"); //jedis.setnx(key,value) //stringRedisTemplate.expire(lockKey,30, TimeUnit.SECONDS); /*Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, clientId, 30, TimeUnit.SECONDS); if (!result) { return "1001"; }*/ // 加锁,实现锁续命功能 redissonLock.lock(); int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock")); // jedis.get("stock") if (stock > 0) { int realStock = stock - 1; stringRedisTemplate.opsForValue().set("stock", realStock + ""); // jedis.set(key,value) System.out.println("扣减成功,剩余库存:" + realStock + ""); } else { System.out.println("扣减失败,库存不足"); } }finally { redissonLock.unlock(); /*if (clientId.equals(stringRedisTemplate.opsForValue().get(lockKey))){ stringRedisTemplate.delete(lockKey); }*/ } return "end"; } @RequestMapping("/redlock") public String redlock() throws InterruptedException { String lockKey = "product_001"; //这里需要自己实例化不同redis实例的redisson客户端连接,这里只是伪代码用一个redisson客户端简化了 RLock lock1 = redisson.getLock(lockKey); RLock lock2 = redisson.getLock(lockKey); RLock lock3 = redisson.getLock(lockKey); /** * 根据多个 RLock 对象构建 RedissonRedLock (最核心的差别就在这里) */ RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3); try { /** * 4.尝试获取锁 * waitTimeout 尝试获取锁的最大等待时间,超过这个值,则认为获取锁失败 * leaseTime 锁的持有时间,超过这个时间锁会自动失效(值应设置为大于业务处理的时间,确保在锁有效期内业务能处理完) */ boolean res = redLock.tryLock(10, 30, TimeUnit.SECONDS); if (res) { //成功获得锁,在这里处理业务 } } catch (Exception e) { throw new RuntimeException("lock fail"); } finally { //无论如何, 最后都要解锁 redLock.unlock(); } return "end"; } }