此文是我看尚硅谷教学视频后的个人的redis学习笔记,每一张截图都是我亲自敲后截图放在笔记中的,粘贴在博客上可能会有点点模糊,若有错误或不足,还望各位大神多多指正!
10 Redis的Java客户端Jedis简单使用
10.1 Jedis所需要的jar包
① commons-pool-1.6.jar
② jedis-2.1.0.jar
③ Pom依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.3.2</version>
</dependency>
10.2 Jedis常用操作
10.2.1 测试连通性
/**
* 测试是否连通
*/
public void connectTest(){
//连接本地的Redis服务
Jedis jedit=new Jedis("127.0.0.1",6379);
//查看服务是否运行,打出pong表示OK
System.out.println("连接返回的值为:"+jedit.ping());
}
10.2.1 5+1
package com.example.pay.payTest;
import redis.clients.jedis.BinaryClient;
import redis.clients.jedis.Jedis;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class test {
public static void main(String[] args) throws InterruptedException {
//连接本地的Redis服务
Jedis jedis=new Jedis("127.0.0.1",6379);
test test=new test();
//test.connectTest(jedis);
//test.keyTest(jedis);
//test.stringTest(jedis);
//test.listTest(jedis);
//test.setTest(jedis);
//test.hashTest(jedis);
test.zsetTest(jedis);
}
/**
* 测试是否连通
*/
public void connectTest(Jedis jedis){
//查看服务是否运行,打出pong表示OK
System.out.println("连接返回的值为:"+jedis.ping());
}
/**
* key常用命令练习
*/
public void keyTest(Jedis jedis) throws InterruptedException {
//新增
jedis.flushAll();
jedis.set("k1","1");
jedis.set("k2","2");
jedis.set("k3","3");
//查询所有的key
Set<String> set=jedis.keys("*");
Iterator iter = set.iterator();
while (iter.hasNext()){
System.out.println((String) iter.next());
}
//判断某个key是否存在
System.out.println(jedis.exists("k2"));
//把k2移动到3号库
jedis.move("k2",2);
//设定k3三秒过期
jedis.expire("k3",10);
Thread.sleep(5000);
//查看k3还有多久过期
System.out.println("k3还有"+jedis.ttl("k3")+"秒过期");
//查看k1的数据类型
System.out.println("k1的数据类型是:"+jedis.type("k1") );
}
/**
*String常用命令练习
*/
public void stringTest(Jedis jedis) throws InterruptedException {
//set:增
jedis.flushAll();
jedis.set("k1","1");
jedis.set("k2","2");
jedis.set("k3","3");
//get:查
System.out.println("k1的value:"+jedis.get("k1"));
//del:删
jedis.del("k3");
//append:拼接
jedis.append("k2","asdfqwer");
System.out.println("新的k2的value:"+jedis.get("k2"));
//strlen:获得指定key的长度
System.out.println("k2的长度:"+jedis.strlen("k2"));
//incr:每次+1
for(int i=0;i<3;i++){
jedis.incr("k1");
}
System.out.println("incr后k1的value:"+jedis.get("k1"));
//incrBy:按指定数增长
System.out.println("incrBy后k1的value:"+jedis.incrBy("k1",2));
//decr:每次-1
System.out.println("decr后k1的value:"+jedis.decr("k1"));
//decrBy:按指定数减少
System.out.println("decryBy后k1的value"+jedis.decrBy("k1",2));
//getrange:得到区间范围的值
jedis.set("k4","abcdefghijklmn");
System.out.println("k4 0~2的值是:"+jedis.getrange("k4",0,2));
//setrange:设置区间值
jedis.setrange("k4",0,"000");
System.out.println("设置了区间值后的K4的value:"+jedis.get("k4"));
//setex:设置带过期时间得key
jedis.setex("k5",1,"5");
Thread.sleep(2000);
long num=jedis.ttl("K5");
if(num==-2){
System.out.println("k5已经过期");
}else{
System.out.println("k5还有"+num+"秒过期");
}
//setnx:只有在 key 不存在时设置 key 的值。
jedis.set("k6","6");
long numm=jedis.setnx("k6","66");
if(numm==0){
System.out.println("k6已经存在了。");
}
//mset:同时设置一个或多个 key-value 对
jedis.mset("k7","7","k8","8","k9","9","k10","10");
Set<String> set=jedis.keys("*");
Iterator iter = set.iterator();
System.out.println("存在的key:");
while (iter.hasNext()){
System.out.print((String) iter.next()+" ");
}
System.out.println("");
//mget:获取所有给定 key 的值。
System.out.println("获取的k1,k2,k4的value分别是:"+jedis.mget("k1","k2","k4"));
//getset:将给定 key 的值设为 value ,并返回 key 的旧值(old value)。
System.out.println("k1旧的值是:"+jedis.getSet("k1","10"));
}
/**
* List常用命令练习
*/
public void listTest(Jedis jedis){
//lpush
jedis.flushAll();
jedis.lpush("k1","1","2","3","4","5");
System.out.println("k1从左边push后的值:"+jedis.lrange("k1",0,-1));
//rpush
jedis.rpush("k2","1","2","3","4","5");
System.out.println("k2从右边push后的值:"+jedis.lrange("k2",0,-1));
//lpop
System.out.println("k1栈顶出去的值:"+jedis.lpop("k1"));
//rpop
System.out.println("k2栈尾出去的值:"+jedis.rpop("k2"));
//lindex:按照索引下标获得元素(从上到下)
System.out.println("k1的值"+jedis.lrange("k1",0,-1));
System.out.println("k1下标为1的值:"+jedis.lindex("k1",1));
//llen:取长度
System.out.println("k1的长度:"+jedis.llen("k1"));
//lrem:删N个value
jedis.rpush("k3","1","1","1","2","2","2","2","3","3","3");
jedis.lrem("k3",2,"3");
System.out.println("删除了2个3后的k3的值:"+jedis.lrange("k3",0,-1));
//ltrim:截取指定范围的值后再赋值给key
jedis.ltrim("k3",0,4);
System.out.println("k3新的值为:"+jedis.lrange("k3",0,-1));
//rpoplpush:把源列表最后一位弹出放到目标列表的第一位
jedis.rpush("k4","a","a","b","b","c","c");
jedis.rpoplpush("k3","k4");
System.out.println("此时k3的值:"+jedis.lrange("k3",0,-1));
System.out.println("此时k4的值:"+jedis.lrange("k4",0,-1));
//lset:修改指定下标的值
jedis.lset("k1",1,"h");
System.out.println("修改指定下标后k1的值:"+jedis.lrange("k1",0,-1));
//linsert:在指定值前插入数据
jedis.linsert("k1",BinaryClient.LIST_POSITION.BEFORE,"2","java");
System.out.println("修改后的k1的值:"+jedis.lrange("k1",0,-1));
}
/**
* Set常用命令练习
*/
public void setTest(Jedis jedis){
jedis.flushAll();
//sadd:增
jedis.sadd("k1","1","2","3","4","5","1");//不会存入重复值
System.out.println("k1的值为:"+jedis.smembers("k1"));
//sismember:判断是否存在
System.out.println("2是k1的值:"+jedis.sismember("k1","2"));
//scard:获取集合里面的元素个数
System.out.println("k1值的个数:"+jedis.scard("k1"));
//srem:删除集合中元素
jedis.srem("k1","1");
System.out.println("删除掉1后的k1的值:"+jedis.smembers("k1"));
//srandmember:随机出数
System.out.println("k1随机出的值:"+jedis.srandmember("k1"));
//spop:随机出栈
System.out.println("k1随机出栈的是:"+jedis.spop("k1"));
//smove key1 key2 在key1里某个值:将key1里的某个值赋给key2
jedis.sadd("k2","a","b","c","d");
jedis.smove("k1","k2","2");
System.out.println("k1的值:"+jedis.smembers("k1"));
System.out.println("k2的值:"+jedis.smembers("k2"));
//sdiff:差集
jedis.sadd("k3","1","2","3","4","5");
jedis.sadd("k4","1","2","3","a","b");
System.out.println("k3和k4的差集是:"+jedis.sdiff("k3","k4"));
System.out.println("k4和k3的差集是:"+jedis.sdiff("k4","k3"));
//sinter:交集
System.out.println("k3和k4的交集是:"+jedis.sinter("k3","k4"));
//sunion:并集
System.out.println("k3和k4的并集是:"+jedis.sunion("k3","k4"));
}
/**
* Hash常用命令练习
* KV模式不变,但Value是一个键值对
*/
public void hashTest(Jedis jedis){
jedis.flushAll();
//hset:增
jedis.hset("k1","name","zhangsan");
//hget:查
System.out.println("k1的值:"+jedis.hget("k1","name"));
//hmset:一次增多个
Map<String,String> hmap=new HashMap<>();
hmap.put("id","1");
hmap.put("name","王五");
hmap.put("age","20");
jedis.hmset("k2",hmap);
//hmget:一次查多个
System.out.println("k2的多个值:"+jedis.hmget("k2","age","name"));
//hgetall:查所有
System.out.println("k2的所有值:"+jedis.hgetAll("k2"));
//hdel:删除指定的
jedis.hdel("k2","age","name");
System.out.println("删除数据后的k2的所有值:"+jedis.hgetAll("k2"));
//hlen:长度
Map<String,String> hhmap=new HashMap<>();
hhmap.put("id","2");
hhmap.put("name","王六");
hhmap.put("age","20");
jedis.hmset("k3",hhmap);
System.out.println("k3的长度:"+jedis.hlen("k3"));
//hexists key:在key里面的某个值的key
System.out.println("k3中是否存在age:"+jedis.hexists("k3","age"));
//hkeys:根据key获取value里所有的key
System.out.println("k3里所有的值的key:"+jedis.hkeys("k3"));
//hvals:根据key获取value里所有的value
System.out.println("k3里所有的值的value:"+jedis.hvals("k3"));
//hincrby:在某个值的基础上加多少
jedis.hincrBy("k3","age",2);
System.out.println("k3的age加了2后:"+jedis.hget("k3","age"));
//hsetnx:不存在赋值,存在了无效
long num=jedis.hsetnx("k3","age","50");
if(num==0){
System.out.println("k3已经存在age了");
}
}
/**
* Zset(sorted set)常用命令练习
*/
public void zsetTest(Jedis jedis){
jedis.flushAll();
//zadd:增
jedis.zadd("k1",10.0,"v1");
Map<Double, String> scoreMap=new HashMap<>();
scoreMap.put(20.0,"v2");
scoreMap.put(30.0,"v3");
scoreMap.put(40.0,"v4");
jedis.zadd("k1",scoreMap);
//zrange:查
System.out.println("k1的值:"+jedis.zrange("k1",0,-1));
//zrangebyscore key 开始score 结束score:范围查
System.out.println("k1 20.0到40.0的值:"+jedis.zrangeByScore("k1",20.0,40.0));
System.out.println("k1 20.0到40.0的值:"+jedis.zrangeByScore("k1",20.0,40.0,2,2));
//zrem key 某score下对应的value值:删除元素
jedis.zrem("k1","v4");
System.out.println("删除掉v4后k1的值:"+jedis.zrange("k1",0,-1));
//zcard :获取集合中元素个数
System.out.println("k1中的元素个数:"+jedis.zcard("k1"));
//zcount :获取分数区间内元素个数,zcount key 开始分数区间 结束分数区间
System.out.println("k1中10.0~30.0元素的个数:"+jedis.zcount("k1",10.0,30.0));
//zrank: 获取value在zset中的下标位置
System.out.println("k1中v2的下标位置:"+jedis.zrank("k1","v2"));
//zscore:按照值获得对应的分数
System.out.println("k1中v2的分数:"+jedis.zscore("k1","v2"));
// zrevrank key values值:逆序获得下标值
System.out.println("k1的v3逆序下标值:"+jedis.zrevrank("k1","v3"));
//zrevrange:倒叙排列
System.out.println("k1的逆序排列:"+jedis.zrevrange("k1",0,-1));
}
}
10.2.1 事务提交
① 日常操作
package com.atguigu.redis.test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Response;
import redis.clients.jedis.Transaction;
public class Test03
{
public static void main(String[] args)
{
Jedis jedis = new Jedis("127.0.0.1",6379);
//监控key,如果改动了事务就被放弃
/*3
jedis.watch("serialNum");
jedis.set("serialNum","s#####################");
jedis.unwatch();*/
Transaction transaction = jedis.multi();//被当作一个命令进行执行
Response<String> response = transaction.get("serialNum");
transaction.set("serialNum","s002");
response = transaction.get("serialNum");
transaction.lpush("list3","a");
transaction.lpush("list3","b");
transaction.lpush("list3","c");
transaction.exec();
//2 transaction.discard();
System.out.println("serialNum***********"+response.get());
}
}
② 加锁操作
public class TestTransaction {
public boolean transMethod() {
Jedis jedis = new Jedis("127.0.0.1", 6379);
int balance;// 可用余额
int debt;// 欠额
int amtToSubtract = 10;// 实刷额度
jedis.watch("balance");
//jedis.set("balance","5");//此句不该出现,讲课方便。模拟其他程序已经修改了该条目
balance = Integer.parseInt(jedis.get("balance"));
if (balance < amtToSubtract) {
jedis.unwatch();
System.out.println("modify");
return false;
} else {
System.out.println("***********transaction");
Transaction transaction = jedis.multi();
transaction.decrBy("balance", amtToSubtract);
transaction.incrBy("debt", amtToSubtract);
transaction.exec();
balance = Integer.parseInt(jedis.get("balance"));
debt = Integer.parseInt(jedis.get("debt"));
System.out.println("*******" + balance);
System.out.println("*******" + debt);
return true;
}
}
/**
* 通俗点讲,watch命令就是标记一个键,如果标记了一个键, 在提交事务前如果该键被别人修改过,那事务就会失败,这种情况通常可以在程序中
* 重新再尝试一次。
* 首先标记了键balance,然后检查余额是否足够,不足就取消标记,并不做扣减; 足够的话,就启动事务进行更新操作,
* 如果在此期间键balance被其它人修改, 那在提交事务(执行exec)时就会报错, 程序中通常可以捕获这类错误再重新执行一次,直到成功。
*/
public static void main(String[] args) {
TestTransaction test = new TestTransaction();
boolean retValue = test.transMethod();
System.out.println("main retValue-------: " + retValue);
}
}
10.2.1 主从复制
public static void main(String[] args) throws InterruptedException
{
Jedis jedis_M = new Jedis("127.0.0.1",6379);
Jedis jedis_S = new Jedis("127.0.0.1",6380);
jedis_S.slaveof("127.0.0.1",6379);
jedis_M.set("k6","v6");
Thread.sleep(500);
System.out.println(jedis_S.get("k6"));
}
① 6379,6380启动,先各自先独立
② 主写
③ 从读
10.3 JedisPool
① 获取Jedis实例需要从JedisPool中获取
② 用完Jedis实例需要返还给JedisPool
③ 如果Jedis在使用过程中出错,则也需要还给JedisPool
④ 案例见代码
JedisPoolUtil
package com.atguigu.redis.test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class JedisPoolUtil {
private static volatile JedisPool jedisPool = null;//被volatile修饰的变量不会被本地线程缓存,对该变量的读写都是直接操作共享内存。
private JedisPoolUtil() {}
public static JedisPool getJedisPoolInstance()
{
if(null == jedisPool)
{
synchronized (JedisPoolUtil.class)
{
if(null == jedisPool)
{
JedisPoolConfig poolConfig = new JedisPoolConfig();//配置池
poolConfig.setMaxActive(1000); //最大链接数
poolConfig.setMaxIdle(32); //最大空闲
poolConfig.setMaxWait(100*1000);//最大等待时间
poolConfig.setTestOnBorrow(true);
jedisPool = new JedisPool(poolConfig,"127.0.0.1");//jedis连接池的配置
}
}
}
return jedisPool;
}
//关闭链接池,释放对象,用完了还回去
public static void release(JedisPool jedisPool,Jedis jedis){
if(null != jedis){
jedisPool.returnResourceObject(jedis);
}
}
}
Demo5 jedisPool.getResource();
package com.atguigu.redis.test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class Test01 {
public static void main(String[] args) {
JedisPool jedisPool = JedisPoolUtil.getJedisPoolInstance();//从池子中拿到对象
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.set("k18","v183");
} catch (Exception e) {
e.printStackTrace();
}finally{
JedisPoolUtil.release(jedisPool, jedis);//把对象还回去,释放对象
}
}
}
⑤ 配置总结all
JedisPool的配置参数大部分是由JedisPoolConfig的对应项来赋值的。
maxActive:控制一个pool可分配多少个jedis实例,通过pool.getResource()来获取;如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted。
maxIdle:控制一个pool最多有多少个状态为idle(空闲)的jedis实例;
whenExhaustedAction:表示当pool中的jedis实例都被allocated完时,pool要采取的操作;默认有三种。
WHEN_EXHAUSTED_FAIL –> 表示无jedis实例时,直接抛出NoSuchElementException;
WHEN_EXHAUSTED_BLOCK –> 则表示阻塞住,或者达到maxWait时抛出JedisConnectionException;
WHEN_EXHAUSTED_GROW –> 则表示新建一个jedis实例,也就说设置的maxActive无用;
maxWait:表示当borrow一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛JedisConnectionException;
testOnBorrow:获得一个jedis实例的时候是否检查连接可用性(ping());如果为true,则得到的jedis实例均是可用的;
testOnReturn:return 一个jedis实例给pool时,是否检查连接可用性(ping());
testWhileIdle:如果为true,表示有一个idle object evitor线程对idle object进行扫描,如果validate失败,此object会被从pool中drop掉;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义;
timeBetweenEvictionRunsMillis:表示idle object evitor两次扫描之间要sleep的毫秒数;
numTestsPerEvictionRun:表示idle object evitor每次扫描的最多的对象数;
minEvictableIdleTimeMillis:表示一个对象至少停留在idle状态的最短时间,然后才能被idle object evitor扫描并驱逐;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义;
softMinEvictableIdleTimeMillis:在minEvictableIdleTimeMillis基础上,加入了至少minIdle个对象已经在pool里面了。如果为-1,evicted不会根据idle time驱逐任何对象。如果minEvictableIdleTimeMillis>0,则此项设置无意义,且只有在timeBetweenEvictionRunsMillis大于0时才有意义;
lifo:borrowObject返回对象时,是采用DEFAULT_LIFO(last in first out,即类似cache的最频繁使用队列),如果为False,则表示FIFO队列;
其中JedisPoolConfig对一些参数的默认设置如下:
testWhileIdle=true
minEvictableIdleTimeMills=60000
timeBetweenEvictionRunsMillis=30000
numTestsPerEvictionRun=-1