目录
以下总结了关于Redis比较全面的知识笔记以及面试题,方便自己复习的同时希望对大家有所帮助。
概括
Jedis是Redis官方提供的Java连接开发工具,使用Java操作Redis的中间件,其实就是一个jar包,里面集成了 redis 的一些命令操作,封装了对 redis 命令的 Java 客户端,如果要使用Java操作Redis,那么一定要熟悉Jedis。
Jedis的基本使用
首先我们创建一个Maven项目进行测试。
1、导包
- 首先在pom文件中倒入依赖(Maven中央仓库):
<!--导入Jedis包-->
<dependencies>
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.3.0</version>
</dependency>
</dependencies>
2、测试ping
- 接下来便是进行代码的测试
public class TestPing {
public static void main(String[] args) {
//(1) new Jedis对象
Jedis jedis = new Jedis("192.168.15.133",6379);
//(2)Jedis对象中的方法就是之前学过的命令
System.out.println( jedis.ping() );
//(3)断开连接
jedis.close();
}
}
- 输出:
- 步骤:
首先连接数据库,创建Jedis对象,然后调用Jedis对象中的对应方法进行测试,最后测试完毕要断开连接。
3、测试Key
public static void main(String[] args) {
Jedis jedis = new Jedis("192.168.15.133",6379);
System.out.println("清空数据:"+jedis.flushDB());
System.out.println("判断某个键是否存在:"+jedis.exists("username"));
System.out.println("新增<'username','oldou'>的键值对:"+jedis.set("username","oldou"));
System.out.println("新增<'password','123456'>的键值对:"+jedis.set("password","123456"));
System.out.println("系统中所有的键如下所示:");
Set<String> keys = jedis.keys("*");
System.out.println(keys);
System.out.println("删除键password:"+jedis.del("password"));
System.out.println("判断键password是否存在:"+jedis.exists("password"));
System.out.println("查看键username所存储的值类型:"+jedis.type("username"));
System.out.println("随机返回key空间中的一个:"+jedis.randomKey());
System.out.println("重命名key:"+jedis.rename("username","name"));
System.out.println("获取修改后的name中的值:"+jedis.get("name"));
System.out.println("按照索引查询:"+jedis.select(0));
System.out.println("删除当前数据库中所有的key:"+jedis.flushDB());
System.out.println("返回当前数据库中key的数目:"+jedis.dbSize());
System.out.println("删除所有数据库中的所有key:"+jedis.flushAll());
System.out.println("断开与Redis的连接:jedis.close()");
jedis.close();
}
- 输出:
4、测试String类型
public class TestString {
public static void main(String[] args) {
Jedis jedis = new Jedis("192.168.15.133",6379);
jedis.flushDB();
System.out.println("=====增加数据======");
System.out.println(jedis.set("key1","value1"));
System.out.println(jedis.set("key2","value2"));
System.out.println(jedis.set("key3","value3"));
System.out.println("查看所有的键:");
Set<String> keys = jedis.keys("*");
System.out.println(keys);
System.out.println("删除key2:"+jedis.del("key2"));
System.out.println("获取键key2:"+jedis.get("key2"));
System.out.println("修改键key1中的值:"+jedis.set("key1","valuechanged"));
System.out.println("获取key1中的值:"+jedis.get("key1"));
System.out.println("在key3的后面加入值:"+jedis.append("key1","End..."));
System.out.println("获取key3中的值:"+jedis.get("key3"));
System.out.println("新增多个键值对:"+jedis.mset("k1","v1","k2","v2","k3","v3"));
System.out.println("获取多个键值对:"+jedis.mget("k1","k2","k3"));
System.out.println("删除多个键值对:"+jedis.del("k1","k2","k3"));
System.out.println("获取多个键值对:"+jedis.mget("k1","k2","k3"));
jedis.flushDB();
System.out.println("============新增键值对防止覆盖原先值============");
System.out.println(jedis.setnx("key1","value1"));
System.out.println(jedis.setnx("key2","value2"));
System.out.println(jedis.setnx("key2","value2-new"));
System.out.println(jedis.get("key1")+"....."+jedis.get("key2"));
System.out.println("=============新增键值对并设置有效时间=====================");
System.out.println(jedis.setex("username",10,"oldou"));
System.out.println(jedis.get("username"));
try{
TimeUnit.SECONDS.sleep(12);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(jedis.get("username"));
System.out.println("===============获取原值,更新为新值=================");
System.out.println(jedis.getSet("key2","key2GetSet"));
System.out.println(jedis.get("key2"));
System.out.println("获取key2中值的字符串:"+jedis.getrange("key2",2,4));
jedis.close();
}
}
5、测试List类型
public class TestList {
public static void main(String[] args) {
Jedis jedis = new Jedis("192.168.15.133",6379);
jedis.flushDB();
System.out.println("===========添加一个List===========");
jedis.lpush("collections","ArrayList","LinkedList","vector","Stack","HashSet");
jedis.lpush("collections","LinkedHashSet");
jedis.lpush("collections","HashSet");
jedis.lpush("collections","TreeSet");
System.out.println("collections的内容:"+jedis.lrange("collections",0,-1));
System.out.println("collections区间中0-3的元素:"+jedis.lrange("collections",0,3));
System.out.println("=====================================");
//删除列表中指定的值,第二个参数为删除的个数(有重复值时,后add进去的值先被删除,类似于出栈)
System.out.println("删除指定元素个数:"+jedis.lrem("collections",2,"HashSet"));
System.out.println("collections的内容:"+jedis.lrange("collections",0,-1));
System.out.println("删除下标0-3区间之外的元素:"+jedis.ltrim("collections",0,3));
System.out.println("collections中的内容为:"+jedis.lrange("collections",0,-1));
System.out.println("collections列表出栈操作(左端):"+jedis.lpop("collection"));
System.out.println("collections中的内容为:"+jedis.lrange("collections",0,-1));
System.out.println("collections添加元素,从列表右端添加:"+jedis.rpush("collections","List","HashSet"));
System.out.println("collections中的内容为:"+jedis.lrange("collections",0,-1));
System.out.println("collections列表出栈操作(右端):"+jedis.rpop("collectiona"));
System.out.println("collections中的内容为:"+jedis.lrange("collections",0,-1));
System.out.println("修改collections指定下标1中的内容:"+jedis.lset("collections",1,"HashMap"));
System.out.println("collections中的内容为:"+jedis.lrange("collections",0,-1));
System.out.println("========================================");
System.out.println("collections中的长度为:"+jedis.llen("collections"));
System.out.println("获取collections下标为2的元素:"+jedis.lindex("collections",2));
System.out.println("================================");
jedis.lpush("sortedList","1","7","3","4","0","9");
System.out.println("sortedList排序前:"+jedis.lrange("sortedList",0,-1));
System.out.println(jedis.sort("sortedList"));
System.out.println("sortedList排序后:"+jedis.lrange("sortedList",0,-1));
jedis.flushDB();
jedis.close();
}
}
6、测试Set类型
public class TestSet {
public static void main(String[] args) {
Jedis jedis = new Jedis("192.168.15.133",6379);
jedis.flushDB();
System.out.println("===============向集合中添加元素(不重复)================");
System.out.println(jedis.sadd("eleSet","e1","e7","e3","e2","e5","e8"));
System.out.println(jedis.sadd("eleSet","e6"));
System.out.println(jedis.sadd("eleSet","e6"));
System.out.println("eleSet集合中所有的元素为:"+jedis.smembers("eleSet"));
System.out.println("删除一个元素e1:"+jedis.srem("eleSet","e1"));
System.out.println("eleSet集合中所有的元素为:"+jedis.smembers("eleSet"));
System.out.println("删除两个元素e6和e3:"+ jedis.srem("eleSet","e6","e3"));
System.out.println("eleSet集合中所有的元素为:"+jedis.smembers("eleSet"));
System.out.println("随机移除集合中的一个元素:"+jedis.spop("eleSet"));
System.out.println("随机移除集合中的一个元素:"+jedis.spop("eleSet"));
System.out.println("eleSet集合中所有的元素为:"+jedis.smembers("eleSet"));
System.out.println("eleSet中包含的元素个数为:"+jedis.scard("eleSet"));
System.out.println("e3是否在eleSet集合中:"+jedis.sismember("eleSet","e3"));
System.out.println("e1是否在eleSet集合中:"+jedis.sismember("eleSet","e1"));
System.out.println("e5是否在eleSet集合中:"+jedis.sismember("eleSet","e5"));
System.out.println("============================================");
System.out.println(jedis.sadd("mySet1","A","B","C","D","E","F","G"));
System.out.println(jedis.sadd("mySet2","H","B","Q","D","G","U","L"));
System.out.println("从mySet1中删除A元素并且存入mySet3中:"+jedis.smove("mySet1","mySet3","A"));
System.out.println("从mySet2中删除H元素并且存入mySet3中:"+jedis.smove("mySet2","mySet3","H"));
System.out.println("mySet1中的元素为:"+jedis.smembers("mySet1"));
System.out.println("mySet3中的元素为:"+jedis.smembers("mySet3"));
System.out.println("==================集合运算====================");
System.out.println("mySet1中的元素为:"+jedis.smembers("mySet1"));
System.out.println("mySet2中的元素为:"+jedis.smembers("mySet2"));
System.out.println("mySet1和mySet2中的元素交集为:"+jedis.sinter("mySet1","mySet2"));
System.out.println("mySet1和mySet2中的元素差集为:"+jedis.sunion("mySet1","mySet2"));
System.out.println("mySet1和mySet2中的元素并集为:"+jedis.sdiff("mySet1","mySet2"));
//将mySet1和mySet2的交集保存到mySet4集合当中
jedis.sinterstore("mySet4","mySet1","mySet2");
System.out.println("mySet4集合中的元素为:"+jedis.smembers("mySet4"));
jedis.flushDB();
jedis.close();
}
}
7、测试Hash类型
public class TestHash {
public static void main(String[] args) {
Jedis jedis = new Jedis("192.168.15.133",6379);
jedis.flushDB();
Map<String,String> map = new HashMap<>();
map.put("key1","value1");
map.put("key2","value2");
map.put("key3","value3");
map.put("key4","value4");
//添加名称为hash(key)的hash元素。
jedis.hset("hash",map);
//向名称为hash的hash中添加key为key5,value为value5的元素
jedis.hset("hash","key5","value5");
System.out.println("散列表hash中的所有键值对为:"+jedis.hgetAll("hash"));
System.out.println("散列表hash的所有键为:"+jedis.hkeys("hash"));
System.out.println("散列表hash的所有键为:"+jedis.hvals("hash"));
System.out.println("将key6保存的值加上一个整数,如果key6不存在就添加key6:"+jedis.hincrBy("hash","key6",10));
System.out.println("散列表hash中所有的键值对为:"+jedis.hgetAll("hash"));
System.out.println("将key6保存的值加上一个整数,如果key6不存在就添加key6:"+jedis.hincrBy("hash","key6",999));
System.out.println("散列表hash中所有的键值对为:"+jedis.hgetAll("hash"));
System.out.println("删除一个或者多个键值对:"+jedis.hdel("hash","key2"));
System.out.println("散列表hash中所有的键值对为:"+jedis.hgetAll("hash"));
System.out.println("散列表hash中键值对的个数为:"+jedis.hlen("hash"));
System.out.println("散列表hash中是否存在key2:"+jedis.hexists("hash","key2"));
System.out.println("散列表hash中是否存在key1:"+jedis.hexists("hash","key1"));
System.out.println("获取散列表hash中的多个值:"+jedis.hmget("hash","key1","key5","key6"));
jedis.flushDB();
jedis.close();
}
}
总结
Jedis基本使用比较简单,只需要在每次使用的时候,创建Jedis对象就可以了。当Jedis对象构建好时,Jedis的底层会打开一条Socket通道和Redis服务进行连接,因此在使用完Jedis对象之后,需要调用Jedis.close()方法把连接关闭,不然会占用系统CPU。当然,如果应用非常平凡的创建和销毁Jedis对象,对应用的性能是很大影响的,因为构建Socket的通道是很耗时的(类似数据库连接)。我们应该使用连接池来减少Socket对象的创建和销毁过程。
JedisPool(连接池)的使用
介绍
Jedis连接池是基于apache-commons pool2实现的。在构建连接池对象的时候,需要提供池对象的配置对象,及JedisPoolConfig(继承自GenericObjectPoolConfig)。我们可以通过这个配置对象对连接池进行相关参数的配置(如最大连接数,最大空数等)。
为什么要使用连接池?
Redis是一种非关系型数据库,基于C/S模式,如果需要使用Redis就必须要建立连接,由于C/S模式是一种远程通信的交互模式,因此Redis服务器可以单独作为一个数据库服务器来独立存在。假设Redis服务器与客户端分处在异地,虽然基于内存的Redis数据库有着超高的性能,但是底层的网络通信却占用了一次数据请求的大量时间,因为每次数据交互都需要先建立连接,假设一次数据交互总共用时30ms,超高性能的Redis数据库处理数据所花的时间可能不到1ms,也即是说前期的连接占用了29ms,连接池则可以实现在客户端建立多个链接并且不释放,当需要使用连接的时候通过一定的算法获取已经建立的连接,使用完了以后则还给连接池,这就免去了数据库连接所占用的时间。
连接池的使用
public static void testJedisPool() {
//创建连接池对象
JedisPool pool = new JedisPool("192.168.15.128",6379);
//通过连接池获取Jedis对象
Jedis jedis = pool.getResource();
String hre = jedis.hget("user", "usrname");
System.out.println(hre);
jedis.close();
pool.close();
}
使用Jedis连接池之后,在每次用完连接对象后一定要记得把连接归还给连接池。Jedis对close方法进行了改造,如果是连接池中的连接对象,调用Close方法将会是把连接对象返回到对象池,若不是则关闭连接。以下为Jedis的close方法和JedisPool的getResource()方法的源码:
@Override
public void close() { //Jedis的close方法
if (dataSource != null) {
if (client.isBroken()) {
this.dataSource.returnBrokenResource(this);
} else {
this.dataSource.returnResource(this);
}
} else {
client.close();
}
}
//另外从对象池中获取Jedis链接时,将会对dataSource进行设置
// JedisPool.getResource()方法
public Jedis getResource() {
Jedis jedis = super.getResource();
jedis.setDataSource(this);
return jedis;
}
通过Jedis实现Redis事务
Redis的事务相关知识参考[Redis基本事务操作]这篇文章
事务相关的命令有:MULTI、EXEC、DISCARD、WATCH、UNWATCH。
代码实现
public class TestRedisTX {
public static void main(String[] args) {
Jedis jedis = new Jedis("192.168.15.133",6379);
jedis.flushDB();
JSONObject jsonObject = new JSONObject();
jsonObject.put("hello","world");
jsonObject.put("name","oldou");
//开启事务
Transaction multi = jedis.multi();
String result = jsonObject.toJSONString();
//加乐观锁,对result进行监控
jedis.watch(result);
//有Redis的相关操作加锁,保证健壮性
try {
multi.set("user1",result);
multi.set("user2",result);
//代码抛出异常,事务执行失败
// int i = 1/0;
multi.exec(); //成功则执行事务
} catch (Exception e) {
//如果事务执行失败就进行解锁
//jedis.unwatch();
multi.discard(); //失败则放弃事务
e.printStackTrace();
}finally {
System.out.println(jedis.get("user1"));
System.out.println(jedis.get("user2"));
jedis.close();//关闭连接
}
}
}
输出:
代码中,通过jedis.multi();
开启Redis的事务,jedis.watch(result);
对result进行监控,接下来编写写命令入队列(multi.set("user1",result); multi.set("user2",result);
),当执行multi.exec()
时,Redis会执行队列中的命令,这个时候如果事务执行成功,就会finally中就会输出get到的值,如果事务执行失败,就会进行异常的捕获,同时将监控进行解锁caozuo jedis.unwatch();
,并且放弃本次事务multi.discard()
,最后不管事务执行是否成功,都要将Jedis进行关闭。