Jedis
概述
Jedis:一款java操作redis数据库的工具。是Redis官方推荐的Java连接开发工具。要在Java开发中使用好Redis中间件,必须对Jedis熟悉才能写成漂亮的代码。
使用java连接Redis时,要在Redis的配置文件中设置bind 0.0.0.0
。
Jedis所需的jar包依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.1.0</version>
</dependency>
基本使用
//1. 获取连接
Jedis jedis = new Jedis("localhost",6379);
//2. 操作
jedis.set("username","zhangsan");
//3. 关闭连接
jedis.close();
测试连通性
Jedis的基本使用非常简单,只需要创建Jedis对象的时候指定host,port, password即可。当然,Jedis对象有很多构造方法,都大同小异,只是对应和Redis连接的socket的参数不一样而已。
public class TestRedisPing {
public static void main(String[] args) {
//创建连接
Jedis jedis=new Jedis("192.168.81.130", 6379);
//设置密码 如果没有密码可以不设置
jedis.auth("123456");
//调用 ping方法
String ping = jedis.ping();
//输出PONG
System.out.println(ping);
jedis.close();
}
}
Jedis操作Redis中的数据结构
key
public static void main(String[] args) {
//创建连接
Jedis jedis=new Jedis("192.168.81.130", 6379);
//keys *
Set<String> keys = jedis.keys("*");
for (String key : keys) {
System.out.println(key);
}
//判断是否存在k2
System.out.println("是否存在k2" + jedis.exists("k2"));
jedis.close();
}
string
package com.coydone.redistest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class RedisTest {
private Jedis jedis;
@Before
public void beforeRedis(){
//1. 获取连接
jedis=new Jedis("192.168.81.130", 6379);
}
@After
public void afterRedis(){
//3. 关闭连接
jedis.close();
}
//keys * 查询所有的key
@Test
public void testKeys(){
Set<String> keys = jedis.keys("*");
for (String key : keys) {
System.out.println(key);
}
}
//string操作
@Test
public void testString(){
//2. 操作
//存储
jedis.set("username","zhangsan");
//获取
String username = jedis.get("username");
System.out.println(username);
//可以使用setex()方法存储可以指定过期时间的 key value
//将activecode:hehe键值对存入redis,并且20秒后自动删除该键值对
jedis.setex("activecode",20,"hehe");
jedis.mset("str1", "v1", "str2", "v2", "str3", "v3");
System.out.println(jedis.mget("str1", "str2", "str3"));
}
}
hash
@Test
public void testHash(){
// 存储hash
jedis.hset("user","name","lisi");
jedis.hset("user","age","23");
jedis.hset("user","gender","female");
// 获取hash
String name = jedis.hget("user", "name");
System.out.println(name);
// 获取hash的所有map中的数据
Map<String, String> user = jedis.hgetAll("user");
for (String value : user.values()) {
System.out.println(value);
}
}
list
@Test
public void testList(){
//存储
jedis.lpush("mylist","a","b","c");//从左边存
jedis.rpush("mylist","a","b","c");//从右边存
//范围获取
List<String> list = jedis.lrange("mylist", 0, -1);
for (String element : list) {
System.out.println(element);
}
//弹出
String element1 = jedis.lpop("mylist");//c
System.out.println(element1);
}
set
@Test
public void testSet(){
// set 存储
jedis.sadd("myset","java","php","c++");
//移除
jedis.srem("myset", "php");
System.out.println(jedis.smembers("myset").size());
// set 获取
Set<String> myset = jedis.smembers("myset");
System.out.println(myset);
}
zset
//zset 即为 sortedset
@Test
public void testZset(){
// sortedset 存储
jedis.zadd("mysortedset",3,"亚索");
jedis.zadd("mysortedset",30,"劫");
jedis.zadd("mysortedset",55,"永恩");
// sortedset 获取
Set<String> mysortedset = jedis.zrange("mysortedset", 0, -1);
System.out.println(mysortedset);
}
事务提交
基本操作
public class TestReidsTranaction {
public static void main(String[] args) {
// 创建连接
Jedis jedis = new Jedis("192.168.81.130", 6379);
//监控key,如果改动了事务就被放弃
/*
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());
jedis.close();
}
}
事务加锁
public class TestReidsTranactionLock {
public boolean transMethod() {
Jedis jedis = new Jedis("192.168.81.130", 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");
jedis.close();
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);
jedis.close();
return true;
}
}
/**
* 通俗点讲,watch命令就是标记一个键,如果标记了一个键, 在提交事务前如果该键被别人修改过,那事务就会失败,这种情况通常可以在程序中 重新再尝试一次。
* 首先标记了键balance,然后检查余额是否足够,不足就取消标记,并不做扣减; 足够的话,就启动事务进行更新操作,
* 如果在此期间键balance被其它人修改, 那在提交事务(执行exec)时就会报错, 程序中通常可以捕获这类错误再重新执行一次,直到成功。
*/
public static void main(String[] args) {
TestReidsTranactionLock test = new TestReidsTranactionLock();
boolean retValue = test.transMethod();
System.out.println("main retValue-------: " + retValue);
}
}
主从复制
public class TestReidsMS {
public static void main(String[] args) throws InterruptedException {
// 创建连接
Jedis jedis_M = new Jedis("192.168.120.129", 6379);
Jedis jedis_S = new Jedis("192.168.120.129", 6380);
jedis_S.slaveof("127.0.0.1", 6379);
jedis_M.set("k6", "v6");
Thread.sleep(500);
System.out.println(jedis_S.get("k6"));
jedis_M.close();
jedis_S.close();
}
}
集群连接
public class ClusterConnection{
public static final String HOST = "192.168.81.130";
public static final Integer HOST_IP = "7001";
public static void main(String[] args){
Set<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort(HOST,7001));
nodes.add(new HostAndPort(HOST,7002));
nodes.add(new HostAndPort(HOST,7003));
nodes.add(new HostAndPort(HOST,7004));
nodes.add(new HostAndPort(HOST,7005));
nodes.add(new HostAndPort(HOST,7006));
JedisCluster jedisCluster = new JedisCluster(nodes);
jedisCluster.set("name","zhangsan");
System.out.println(jedisCluster.get("name"));
//关闭连接
jedisCluster.close();
}
}
jedis连接池
jedis连接池是基于apache-commons pool2实现的。在构建连接池对象的时候,需要提供池对象的配置对象,及JedisPoolConfig(继承自GenericObjectPoolConfig)。我们可以通过这个配置对象对连接池进行相关参数的配置(如最大连接数,最大空数等)。
JedisPool使用
package com.coydone.redistest;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
//1. 创建JedisPool连接池对象
//2. 调用方法 getResource()方法获取Jedis连接
public class RedisPoolTest {
public static void main(String[] args) {
//0.创建一个配置对象
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(50);
config.setMaxIdle(10);
//1.创建Jedis连接池对象
JedisPool jedisPool = new JedisPool(config,"192.168.81.130",6379);
//2.获取连接
Jedis jedis = jedisPool.getResource();
//3. 使用
jedis.set("name","zhangsan");
System.out.println(jedis.get("name"));
//4. 关闭 归还到连接池中
jedis.close();
}
}
使用redis存储对象
public class JedisPoolApp {
public static void main(String[] args) {
JedisPoolConfig config = new JedisPoolConfig();
//配置连接池的相关信息
poolConfig.setMaxTotal(100);
poolConfig.setMaxIdle(80);
poolConfig.setMinIdle(20);
poolConfig.setMaxWaitMillis(2000);
JedisPool jedisPool=new JedisPool(config,"192.168.81.130",6379);
//从连接池里面得到连接
Jedis jedis = jedisPool.getResource();
//User类:name address
User user =new User("小明","武汉");
//使用fastjson:对象转json字符串
jedis.set("user:1", JSON.toJSONString(user));
String json = jedis.get("user:1");
System.out.println(json);
//json转对象
User user1=JSON.parseObject(json,User.class);
System.out.println(user1.getName()+" "+user1.getAddress());
jedis.close();//还到池里面
}
}
连接池工具类
//需要加载配置文件jedis.properties
public class JedisPoolUtils {
private static JedisPool jedisPool;
static{
//读取配置文件
InputStream is = JedisPoolUtils.class.getClassLoader().getResourceAsStream("jedis.properties");
//创建Properties对象
Properties pro = new Properties();
//关联文件
try {
pro.load(is);
} catch (IOException e) {
e.printStackTrace();
}
//获取数据,设置到JedisPoolConfig中
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal")));
config.setMaxIdle(Integer.parseInt(pro.getProperty("maxIdle")));
//初始化JedisPool
jedisPool = new JedisPool(config,pro.getProperty("host"),Integer.parseInt(pro.getProperty("port")));
}
/**
* 获取连接方法
*/
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
//直接在代码里进行配置
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.setMaxTotal(1000);
poolConfig.setMaxIdle(32);
poolConfig.setMaxWaitMillis(100 * 1000);
poolConfig.setTestOnBorrow(true);
jedisPool = new JedisPool(poolConfig, "192.168.120.129", 6379);
}
}
}
return jedisPool;
}
public static void release(JedisPool jedisPool, Jedis jedis) {
if (null != jedis) {
Jedis jedis2 = null;
try {
jedis2 = jedisPool.getResource();
} finally {
jedis2.close();
}
}
}
}
//使用
public class TestJedisPool {
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);
}
}
}
JedisPool配置
JedisPool的配置参数大部分是由JedisPoolConfig的对应项来赋值的。
maxTotal/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无用;
setMaxWaitMillis/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
coydone的博客