目录
1:redis基本操作
1.1:redis命令操作
1.2:代码操作
2:redis连接池
2.1引入jar包
2.2 redis.properties配置文件
2.3 连接池代码通用代码
2.4多线程类
2.4测试方法
2.5输出结果和分析
1:redis基本操作
我们知道Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
无论是在windows后者是lunix环境上安装好redis后,我们对redis进行操作一般有两种方,
1.1:redis命令操作
这一种操作一般用于对redis进行一些查询,bug追踪,实施人员维护查询等等情况吧,对于程序开发来说,不采用这种方法,但是这种方法也有自己在特殊情况的用途
String操作方法如下:其他方法类似,如果想详细了解命令的操作方法,请参考Redis 数据类型 | 菜鸟教程
实例:
redis 127.0.0.1:6379> SET name "runoob"
OK
redis 127.0.0.1:6379> GET name
"runoob"
1.2:代码操作
代码操作,主要介绍Java代码操作redis,这种方式是程序开发的主流
在代码中引入maven依赖
<!-- redis依赖jar -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.1</version>
</dependency>
代码操作如下:
package com.thit.redis;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;
public class Test1 {
private Jedis jedis=null;
@Before
public void initJedis(){
//连接本地的 Redis 服务 默认端口号是6379
//阿里云地址
jedis=new Jedis("地址", 6379);
//jedis.auth("123456");
System.out.print("连接成功:");
System.out.println(jedis.ping());
}
/**
* string类型数据的增删改查
*/
@Test
public void Stringtest(){
//新增
jedis.set("name", "张三");
jedis.set("name1", "李四");
System.out.println("redis存储的字符串为:"+jedis.get("name"));
System.out.println("redis存储的字符串为:"+jedis.get("name1"));
//修改拼接键
jedis.append("name", "今年18岁!");
System.out.println("redis存储的字符串为:"+jedis.get("name"));
//设置过期时间
jedis.expire("name", 10);//设置过期时间 以秒为单位
//直接删除
jedis.del("name");
System.out.println("redis存储的字符串为:"+jedis.get("name"));
}
// 连接成功
// PONG
// redis存储的字符串为:张三
// redis存储的字符串为:李四
// redis存储的字符串为:张三今年18岁!
// redis存储的字符串为:null
/**
* list类型数据的增删改查
*
*/
@Test
public void Listtest(){
//不删除的话list会不断插入重复元素
jedis.del("list1");
//新增
jedis.lpush("list1", "尼克.罗宾","女","28.5","西西里岛");
//修改
System.out.println("获取Lisi数据的移除并且获取第一个元素:"+jedis.lpop("list1"));
//在头部添加元素
jedis.lpushx("list1", "在头部插入太元素");
jedis.lpush("list1", "在头部插入太元素1","在头部插入太元素2");
//获取数据
System.out.println("获取Lisi数据长度:"+jedis.llen("list1"));
System.out.println("获取Lisi数据"+jedis.lrange("list1", 0, -1));
}
// 连接成功:PONG
// 获取Lisi数据的移除并且获取第一个元素:西西里岛
// 获取Lisi数据长度:6
// 获取Lisi数据[在头部插入太元素2, 在头部插入太元素1, 在头部插入太元素, 28.5, 女, 尼克.罗宾]
/**
* hash类型数据的增删改查
*/
@Test
public void Hashtest(){
//新增
Map<String, String> map=new HashMap<String, String>();
map.put("name", "张全蛋");
map.put("address", "北京海淀区");
map.put("phone", "113788849231");
map.put("sex", "男");
jedis.hmset("hash1", map);
System.out.println("返回散列中的条目:"+jedis.hlen("hash1"));
System.out.println("返回key是够存在:"+jedis.exists("hash1"));
System.out.println("user对象中的所有key-set:" + jedis.hkeys("hash1"));//返回user对象中的所有key
System.out.println("user对象中的所有value-list:" + jedis.hvals("hash1"));//返回map对象中的所有value
//获取得到hash的单个值和获取多个值
System.out.println(jedis.hget("hash1", "name"));
List<String> ls=jedis.hmget("hash1", "address","phone","sex");
for (String string : ls) {
System.out.println("个人信息:"+string);
}
//删除map里面的某一个值
System.out.println("address删除前:"+jedis.hget("hash1", "address"));
jedis.hdel("hash1", "address");
System.out.println("address删除后:"+jedis.hget("hash1", "address"));
//删除整个key的所有值
jedis.del("hash1");
System.out.println("hash1删除后:"+jedis.hget("hash1", "name"));
}
// 返回散列中的条目:4
// 返回key是够存在:true
// user对象中的所有key-set:[name, address, phone, sex]
// user对象中的所有value-list:[张全蛋, 男, 北京海淀区, 113788849231]
// 张全蛋
// 个人信息:北京海淀区
// 个人信息:113788849231
// 个人信息:男
// address删除前:北京海淀区
// address删除后:null
// hash1删除后:null
/**
* jedis操作Set
* set具有无序性。存储无序数据
*/
@Test
public void Settest(){
//添加
jedis.sadd("set1", "茉莉","88元","中国","秋季","花香","温室");
//获取set的值
System.out.println("获取set的值:"+jedis.smembers("set1"));
//查询长度
System.out.println("获取set的值:"+jedis.scard("set1"));
//移除指定元素
jedis.srem("set1", "茉莉");
System.out.println("获取set的值:"+jedis.smembers("set1"));
}
// 连接成功:PONG
// 获取set的值:[茉莉, 花香, 88元, 中国, 温室, 秋季]
// 获取set的值:6
// 获取set的值:[花香, 88元, 中国, 温室, 秋季]
/**
* jedis操作sorted set
* set具有无序性。存储无序数据
* Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
有序集合的成员是唯一的,但分数(score)却可以重复。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
*/
@Test
public void sortedSettest(){
//添加
jedis.zadd("Zset", 0, "a");
jedis.zadd("Zset", 3, "b");
jedis.zadd("Zset", 8, "c");
jedis.zadd("Zset", 99, "d");
jedis.zadd("Zset", 7, "a");
//分值越小 排序越靠前
System.out.println(jedis.zrange("Zset", 0, 7));//查询
System.out.println(jedis.zcard("Zset"));//查询长度
}
}
以上就是jedis代码最】对redis不同数据类型,String、Hash、List、Set、Sorted set的具体操作。
2:redis连接池
我们知道redis是一种key-value形式的内存数据,他的访问速度非常快速高效,我们大量高频发查询的业务情景很多,这种情况下,我们的消耗主要的反复的对redis建立连接的过程,而不是redis连接后的查询过程,所以类比常规数据库,数据库连接池技术就会变得非常必要。
2.1引入jar包
<!-- redis依赖jar -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.1</version>
</dependency>
<!-- redispool依赖jar -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.0</version>
</dependency>
2.2 redis.properties配置文件
#*****************jedis连接参数设置*********************
#redis服务器ip
redis.ip=地址
#redis服务器端口号
redis.port=6379
#redis访问密码
redis.passWord=test123
#与服务器建立连接的超时时间毫秒
redis.timeout=3000
#************************jedis池参数设置*******************
#jedis的最大连接数,连接池在同一时间能够分配的最大活动连接的数量
jedis.pool.MaxTotal=20
#最大空闲连接:连接池中容许保持空闲状态的最大连接数量,超过的空闲连接将被释放,
#表示即使没有数据库连接时依然可以保持10空闲的连接,而不被清除,随时处于待命状态
jedis.pool.maxIdle=10
#连接池中容许保持空闲状态的最小连接数量,低于这个数量将创建新的连接,如果设置为0则不创建,默认值0
jedis.pool.minIdle=0
#初始化连接数:连接池启动时创建的初始化连接数量,默认值0
jedis.pool.initialSize=0
#jedis池没有连接对象返回时,等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。
#如果超过等待时间,则直接抛出JedisConnectionException
jedis.pool.maxWait=3000
#从池中获取连接的时候,是否进行有效检查
jedis.pool.testOnBorrow=true
#归还连接的时候,是否进行有效检查
jedis.pool.testOnReturn=true
2.3 连接池代码通用代码
package com.thit.redis.pool;
import java.io.IOException;
import java.util.Properties;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class Utilpool {
private static JedisPool jedisPool=null;
private static String pfile="redis.properties";
//把redis连接对象放到本地线程中
private static ThreadLocal<Jedis> local=new ThreadLocal<Jedis>();
//private修饰 不能通过new来创建类的实例
private Utilpool() {}
//初始话连接池参数
static void init() {
JedisPoolConfig config=new JedisPoolConfig();
Properties properties=new Properties();
// String path=Utilpool.class.getClassLoader().getResource("").getPath();
// System.out.println("类加载路径:"+path);
try {
properties.load(Utilpool.class.getClassLoader().getResourceAsStream(pfile));
//设置连接池最大连接
config.setMaxTotal(Integer.valueOf(properties.getProperty("jedis.pool.MaxTotal")));
//最大空闲连接:连接池中保持的最大空闲连接。超过最大连接会被释放
config.setMaxIdle(Integer.valueOf(properties.getProperty("jedis.pool.maxIdle")));
config.setMaxWaitMillis(Integer.valueOf(properties.getProperty("jedis.pool.maxWait")));
jedisPool=new JedisPool(config, properties.getProperty("redis.ip"), Integer.valueOf(properties.getProperty("redis.port")), Integer.valueOf(properties.getProperty("redis.port")), null);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//获取连接
static Jedis getCon(){
Jedis jedis =local.get();
if(jedis==null) {
if(jedisPool==null) {
init();
}
jedis=jedisPool.getResource();
local.set(jedis);
}
return jedis;
}
//关闭连接
static void closeCon() {
//从本地线程获取
Jedis jedis=local.get();
if(jedis!=null) {
jedis.close();
}
local.set(null);
}
//关闭连接池
static void closePool() {
if(jedisPool!=null) {
jedisPool.close();
}
}
}
2.4多线程类
便于同时开启50个线程模拟50个用户同时连接redis.
package com.thit.redis.pool;
import java.text.SimpleDateFormat;
import java.util.Date;
import redis.clients.jedis.Jedis;
/**
* @author 79027
* 继续Thread类
*/
public class ClientThread extends Thread {
int i = 0;
public ClientThread(int i) {
this.i = i;
}
//重写run方法
public void run() {
//获取连接
Jedis jedis=Utilpool.getCon();
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
String time = sdf.format(date);
jedis.set("key", time);
try {
String foo = jedis.get("key");
System.out.println("【输出>>>>】key:" + foo + " 第:"+i+"个线程");
//每一个随机休眠5秒,休眠结束关闭连接
Thread.sleep((int)(Math.random()*5000));
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
// 关闭连接
Utilpool.closeCon();
}
}
}
2.4测试方法
package com.thit.redis.pool;
public class Test1 {
public static void main(String[] args) {
//初始化连接池
System.out.println("=================");
//初始化连接
Utilpool.init();
//同时50个线程进行访问
for (int i = 0; i < 50; i++) {
ClientThread t = new ClientThread(i);
t.start();
}
}
}
2.5输出结果和分析
输出结果截图如下:
输出结果分析:
【输出>>>>】key:2018-11-23 17:25:32:984 第:12个线程
【输出>>>>】key:2018-11-23 17:25:32:984 第:19个线程
【输出>>>>】key:2018-11-23 17:25:32:984 第:9个线程
【输出>>>>】key:2018-11-23 17:25:32:984 第:10个线程
【输出>>>>】key:2018-11-23 17:25:32:984 第:13个线程
【输出>>>>】key:2018-11-23 17:25:32:984 第:2个线程
【输出>>>>】key:2018-11-23 17:25:32:984 第:6个线程
【输出>>>>】key:2018-11-23 17:25:32:984 第:17个线程
【输出>>>>】key:2018-11-23 17:25:32:984 第:5个线程
【输出>>>>】key:2018-11-23 17:25:32:984 第:15个线程
【输出>>>>】key:2018-11-23 17:25:32:984 第:18个线程
【输出>>>>】key:2018-11-23 17:25:32:984 第:1个线程
【输出>>>>】key:2018-11-23 17:25:32:984 第:14个线程
【输出>>>>】key:2018-11-23 17:25:32:984 第:16个线程
【输出>>>>】key:2018-11-23 17:25:32:984 第:3个线程
【输出>>>>】key:2018-11-23 17:25:32:984 第:8个线程
【输出>>>>】key:2018-11-23 17:25:32:984 第:0个线程
【输出>>>>】key:2018-11-23 17:25:32:984 第:4个线程
【输出>>>>】key:2018-11-23 17:25:32:984 第:7个线程
【输出>>>>】key:2018-11-23 17:25:32:984 第:11个线程
连接池20个链接被快速占满,这20个连接开始睡眠,但是睡眠时间是随机的,后30个链接根据等待时间3秒开始等待,
在这三秒中有的连接睡醒了,连接空闲出来 后三十个连连接中的16个进去了连接池拿到了连接,连接池始终是满的,一直连接睡醒,有连接进去
【输出>>>>】key:2018-11-23 17:25:33:193 第:42个线程
【输出>>>>】key:2018-11-23 17:25:33:284 第:30个线程
【输出>>>>】key:2018-11-23 17:25:33:284 第:28个线程
【输出>>>>】key:2018-11-23 17:25:33:318 第:29个线程
【输出>>>>】key:2018-11-23 17:25:33:624 第:27个线程
【输出>>>>】key:2018-11-23 17:25:33:928 第:25个线程
【输出>>>>】key:2018-11-23 17:25:34:066 第:22个线程
【输出>>>>】key:2018-11-23 17:25:34:231 第:21个线程
【输出>>>>】key:2018-11-23 17:25:34:443 第:23个线程
【输出>>>>】key:2018-11-23 17:25:34:515 第:44个线程
【输出>>>>】key:2018-11-23 17:25:34:991 第:41个线程
【输出>>>>】key:2018-11-23 17:25:34:991 第:20个线程
【输出>>>>】key:2018-11-23 17:25:35:323 第:43个线程
【输出>>>>】key:2018-11-23 17:25:35:417 第:40个线程
【输出>>>>】key:2018-11-23 17:25:35:417 第:39个线程
【输出>>>>】key:2018-11-23 17:25:35:604 第:38个线程
【输出>>>>】key:2018-11-23 17:25:35:604 第:37个线程
此处程序会报错,然后接着输出
三秒等待时间结束,还有14个连接等待超时时间3秒过后,13个程序超时显示报错,
偶尔一个程序在3秒等待时间的最后,有其他的连接释放,此连接进去了,进去时间在17:25:35:984之前
【输出>>>>】key:2018-11-23 17:25:35:902 第:35个线程
此时设置的睡眠时间还没有结束,等待睡眠时间结束,程序结束
注意:因为每次的休眠时间是随机的,所以每一次测试结果都是不同的,上述结果是对本人输出结果的分析。