redis学习-32-Java使用Redis(Jedis)

35.Java使用Redis

  • 本节介绍如何在 Java 中使用 Redis步骤,首先需要确定已经安装了 Redis 服务及 Java Redis 驱动,并且能够成功运行 Java 程序。

Jedis:是Redis官方推荐的java连接开发工具!使用Java操作Redis中间件!如果你要使用java操作redis,那么一定要对Jedis十分的熟悉。

35.1 安装Redis驱动
  • 在 Java 环境下操作 Redis ,需要安装相应的 Redis 驱动程序,也就是jedis.jar 包,然后将该驱动添加至 Java 的 classpath 中。
  • 若项目是基于 maven 构建的,那么可以直接导入 maven 坐标,如下所示:
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>4.3.1</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>2.0.5</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
</dependency>
  • 之后就可以进行三步走:
    • 建立链接
    • 命令测试
    • 断开链接
35.2 连接Redis服务器
  • 安装完 Redis 的驱动程序后,接下来就是连接 Redis 服务器。最简单的连接方式,就是通过 Jedis 对象连接。代码如下:

注意之前redis的环境配置:

  • 远程链接 redis的要注意:

    • 1、修改conf文件,把 bind 127.0.0.1那行注释掉,把protected-mode改为 no。
    • 修改改daemonize为守护进程。
    • 远程连接修改完配置文件之后一定要重启redis服务,不要直接exit退出。
  • 需要开启linux服务器的防火墙,加入6379端口放通;2.需要放通服务器安全组的6379端口

  • Jedis 所有的命令就是我们之前学习的所有指令!所以之前的指令学习很重要!

import org.junit.Test;
//引入Redis驱动程序
import redis.clients.jedis.Jedis;

public class TestRedis {

    @Test
    public void testRedisConnection(){
     	//连接本地的 Redis 服务,new Jedis对象即可
        //Jedis jedis = new Jedis("localhost",6379);
    	//连接远程的 Redis 服务
        Jedis jedis = new Jedis("121.x.x.x", 6379);
        // 如果设置 Redis 服务的密码,需要进行验证,若没有则可以省去
        jedis.auth("123456");
        System.out.println("链接成功!");
        //查看服务是否运行
        System.out.println("服务正在运行!"+jedis.ping());

    }
}
  • 首先确保 Redis 驱动包引入路径正确的,然后编译并运行 Java 程序,输出结果如下:
链接成功!
服务正在运行!PONG

Process finished with exit code 0
35.3 Java Redis字符串
  • Redis String 类型操作,示例如下:
import org.junit.Test;
import redis.clients.jedis.Jedis;

public class TestRedis {
	@Test
    public void testRedisSetGet(){
        Jedis jedis = new Jedis("121.x.x.x", 6379);
        jedis.auth("123456");
        System.out.println("链接成功!");
        //设置 redis 字符串数据
        jedis.set("name","tony");
        // 获取存储的数据并输出
        System.out.println("获取key值new:"+jedis.get("name"));
        System.out.println("获取key值num:"+jedis.get("num"));
        System.out.println("获取key的过期时间:"+jedis.ttl("num"));
        jedis.mset("age","18","love","football");
        System.out.println("获取vals"+jedis.mget("num","age","love"));
    }
}
  • 译并运行上述程序,输出结果如下:
链接成功!
获取key值new:tony
获取key值num:55
35.4 Java Redis列表
  • Redis List 列表操作,示例如下:
import org.junit.Test;
import redis.clients.jedis.Jedis;

import java.util.List;

public class TestRedis {
	//Redis List 列表操作
    @Test
    public void testRedisList(){
    	//连接 Redis 服务
        Jedis jedis = new Jedis("121.x.x.x", 6379);
        jedis.auth("123456");
        System.out.println("链接成功!");
        //删除已存在的list同名key
        if (jedis.llen("mycourselist")>0) {
            jedis.del("mycourselist");
        }
        //存储数据到列表中
        jedis.lpush("mycourselist","java");
        jedis.lpush("mycourselist","php");
        jedis.lpush("mycourselist","python");
        jedis.lpush("mycourselist","c#");
         // 获取存储的数据并输出
        List<String> mycourselist = jedis.lrange("mycourselist", 0, -1);
        for (String mycourse:mycourselist) {
            System.out.println("list列表mycourselist中的元素:"+mycourse);
        }
    }
}
  • 编译并运行上述程序,输出结果如下:
链接成功!
list列表mycourselist中的元素:c#
list列表mycourselist中的元素:python
list列表mycourselist中的元素:php
list列表mycourselist中的元素:java

Process finished with exit code 0

35.5 Java Redis键
  • 查看所有 key,示例如下:

    import org.junit.Test;
    import redis.clients.jedis.Jedis;
    
    import java.util.Iterator;
    import java.util.Set;
    
    public class TestRedis {
    	//查看所有 key
        @Test
        public void testRedisKeys(){
        	//连接Redis 服务
            Jedis jedis = new Jedis("121.x.x.x", 6379);
            jedis.auth("123456");
            System.out.println("链接成功!");
            // 获取数据并输出
            Set<String> keys = jedis.keys("*");
            Iterator<String> it = keys.iterator();
            while (it.hasNext()) {
                key = it.next();
                System.out.println("redis服务中的元素key:"+key);
                if (jedis.type(key).toLowerCase().equals("string")) {
                    System.out.println("该元素:"+key+":"+jedis.get(key));
                }
            }
        }
    }
    
  • 编译并运行上述程序。输出结果如下:

链接成功!
redis服务中的元素key:myhash
redis服务中的元素key:city
redis服务中的元素key:num
该元素:num:55
redis服务中的元素key:lesson
redis服务中的元素key:weight
redis服务中的元素key:user:1
redis服务中的元素key:url
该元素:url:www.baidu.com
redis服务中的元素key:name
该元素:name:tony
redis服务中的元素key:mycourselist
redis服务中的元素key:course
redis服务中的元素key:mybit
该元素:mybit:�
redis服务中的元素key:us:name
redis服务中的元素key:value
redis服务中的元素key:user

Process finished with exit code 0
35.6 其他类型set/hash
  • set类型操作
@Test
    public void testRedisSet(){
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        jedis.sadd("lesson","C++","python","hadoop");
        jedis.sadd("lesson","K8S");
        Set<String> lessons = jedis.smembers("lesson");
        Iterator<String> iterator = lessons.iterator();
        while (iterator.hasNext()){
            System.out.println("lesson内容:"+iterator.next());
        }
        jedis.srem("lesson","K8S");
        System.out.println("lesson个数:"+jedis.scard("lesson"));
    }
    --结果--
    lesson内容:c#
    lesson内容:python
    lesson内容:C++
    lesson内容:java
    lesson内容:K8S
    lesson内容:lua
    lesson内容:php
    lesson内容:hadoop
    lesson内容:sql
    lesson个数:8

Process finished with exit code 0

  • Hash类型操作
@Test
    public void testRedisHash(){
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        jedis.hset("user:id:1","name","zs");
        HashMap<String, String> map = new HashMap<>();
        map.put("name","tony");
        map.put("age","18");
        map.put("addr","beijing");
        map.put("sex","boy");
        jedis.hmset("user:id:2",map);
        List<String> result = jedis.hmget("user:id:2", "name", "age", "addr");
        for (String ele :
                result) {
            System.out.println("user:id:2内容:"+ele);
        }
        System.out.println("user:id:1是否存在:"+jedis.exists("user:id:1"));
    }
    --结果--
    user:id:2内容:tony
    user:id:2内容:18
    user:id:2内容:beijing
    user:id:1是否存在:true
  • zset类型取出来的仅有值,没有对应的分数
 @Test
    public void testRedisZset() {
        Jedis jedis = new Jedis("121.x.x.x", 6379);
        jedis.auth("123456");
        System.out.println("链接成功!");
        //删除已存在的list同名zset类型的key
        if (jedis.zcard("height")>0) {
            jedis.del("height");
        }
        jedis.zadd("height",160,"ll");
        jedis.zadd("height",160,"zs");
        jedis.zadd("height",170,"hh");
        jedis.zadd("height",180,"lz");
        jedis.zadd("height",185,"ls");
        jedis.zadd("height",190,"yz");
        jedis.zadd("height",210,"tony");
        List<String> heights = jedis.zrange("height", 0, -1);
        for (String height : heights) {
            System.out.println("zset集合height中的元素:" + height);
        }
    }
    --结果--
    链接成功!
    zset集合height中的元素:ll
    zset集合height中的元素:zs
    zset集合height中的元素:hh
    zset集合height中的元素:lz
    zset集合height中的元素:ls
    zset集合height中的元素:yz
    zset集合height中的元素:tony

35.7 java redis事务
  • redis事务操作比较重要,需要着重讲:

  • 实例操作:需要fastjson需要将jar包提前导入项目。

	@Test
    public void testTx01(){
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("name","zs");
        JSONObject jsonObject2 = new JSONObject();
        jsonObject2.put("name","ls");
        Jedis jedis = new Jedis("121.x.x.x", 6379);
        jedis.auth("xxxxx");
        /*监控key,如果修改了key,则后续事物被放弃
        jedis.watch("num");
        jedis.set("num","20");
        jedis.unwatch();*/
        //开启事务
        Transaction multi = jedis.multi();
        Response<String> user=null;
        try {
            multi.set("user1",jsonObject.toJSONString());
            multi.set("user2",jsonObject2.toJSONString());
            user = multi.get("user1");
            multi.exec();           //执行事务
        }catch (Exception ex){
            multi.discard();        //关闭事务
            ex.printStackTrace();
        }finally {
            System.out.println("user1:"+jedis.get("user1"));
            System.out.println("user2:"+jedis.get("user2"));
            System.out.println(user.get());
            jedis.close();  //关闭链接
        }

    }

##结果
user1:{"name":"zs"}
user2:{"name":"ls"}
{"name":"zs"}
  • 测试事务在不同异常下命令的执行情况。
@Test
    public void testTx02(){
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("name","zs");
        JSONObject jsonObject2 = new JSONObject();
        jsonObject2.put("name","ls");
        Jedis jedis = new Jedis("121.x.x.x", 6379);
        jedis.auth("xxxxx");
        System.out.println("name类型:"+jedis.type("name")+":值:"+jedis.get("name"));
        jedis.del("user1","user2");
       	//开启监控,实现乐观锁
        jedis.watch("user1");
        //开启事务
        Transaction multi = jedis.multi();
        //取消异常捕捉机制
        multi.set("user1",jsonObject.toJSONString());
        //int i = 1 / 0;                            //算数异常,导致事务中其他命令中断执行
        multi.incrBy("name",10);    //命令异常,事务中其他命令可以正常执行
        multi.set("user2",jsonObject2.toJSONString());
        multi.exec();           //执行事务
        //虽然给字符串incrBy命令报错了,但是其他依旧正常执行成功了!
        System.out.println("user1:"+jedis.get("user1"));
        System.out.println("user2:"+jedis.get("user2"));
        jedis.close();  //关闭链接
    }
    
    
//算数异常
name类型:string:值:tony

java.lang.ArithmeticException: / by zero
//命令异常
name类型:string:值:tony
user1:{"name":"zs"}
user2:{"name":"ls"}
  • 简单的资金转移例子
//首先标记了键aAmount,而后检查余额是否足够,不足就取消标记,并不作扣减; 足够的话,就启动事务进行更新操做
    //若是在此期间键aAmount被其它人修改, 那在提交事务(执行exec)时就会报错, 程序中一般能够捕获这类错误再从新执行一次,直到成功
    @Test
    public void testTx03(){
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        jedis.set("aAmount","100");
        jedis.set("bAmount","20");
        System.out.println("操作前A账户余额"+jedis.get("aAmount"));
        System.out.println("操作前B账户余额"+jedis.get("bAmount"));
        Integer aAmount;    //A账户余额
        Integer bAmount;    //B账户余额
        Integer transferSmount = 10;    //转移金额
        jedis.watch("aAmount");
        //jedis.set("aAmount","200");   //可以模拟其他线程修改该变量
        int aAmount1 = Integer.parseInt(jedis.get("aAmount"));
        if (aAmount1 <transferSmount){
            System.out.println("--unmondify--");
            jedis.unwatch();
        }else {
            System.out.println("--mondify--");
            Transaction multi = jedis.multi();
            multi.decrBy("aAmount",transferSmount);
            multi.incrBy("bAmount",transferSmount);
            multi.exec();
        }
        System.out.println("操作后A账户余额"+jedis.get("aAmount"));
        System.out.println("操作后B账户余额"+jedis.get("bAmount"));
    }
    --结果--
    操作前A账户余额100
    操作前B账户余额20
    --mondify--
    操作后A账户余额90
    操作后B账户余额30
35.8 主从复制
  • redis 6379,6380都启动,先各自启动运行
    在这里插入图片描述
    在这里插入图片描述

  • jedis设置主从读写同步

//主从复制
    @Test
    public void testSlave(){
        Jedis jedis_m = new Jedis("127.0.0.1", 6379);
        System.out.println(jedis_m.get("title"));
        //jedis_m.auth("123456");
        Jedis jedis_s = new Jedis("127.0.0.1", 6380);
        //jedis_s.auth("123456");
        jedis_s.replicaof("127.0.0.1", 6379);
        jedis_m.set("m_key1","m_val");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(jedis_s.get("m_key1"));
    }
    
    --结果--
    redis
	m_val

  • 从服务器会进行和主机同步操作
    在这里插入图片描述
35.9 jedis线程池JedisPool
  • 单例封装JedisPoolUtil,实例化JedisPool
public class JedisPoolUtil {

    //被volatile修饰的变量不会被本地线程缓存,对该变量的读写都是直接操作共享内存
    private static volatile JedisPool jedisPool = null;

    public JedisPoolUtil(){}

    public static JedisPool getJedisPoolInstance() {
        if (null == jedisPool){
            synchronized (JedisPoolUtil.class){
                if (null == jedisPool){
                    JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
                    jedisPoolConfig.setMaxTotal(2000);
                    jedisPoolConfig.setMaxIdle(32);
                    jedisPoolConfig.setTestOnBorrow(true);
                    jedisPoolConfig.setMaxWait(Duration.ofMinutes(100000));
                    jedisPool = new JedisPool(jedisPoolConfig, "127.0.0.1");
                }
            }
        }
        return jedisPool;
    }
}
#将jedis返回JedisPool
public static void release(JedisPool jedisPool,Jedis jedis){
        if (jedis != null) {
            jedisPool.returnResource(jedis);
        }
    }
  • 测试
@Test
    public void testJedisPool(){
        JedisPool jedisPoolInstance = JedisPoolUtil.getJedisPoolInstance();
        Jedis jedis = null;
        try {
            jedis = jedisPoolInstance.getResource();
            jedis.set("num","12");
        }catch (Exception ex){
            ex.printStackTrace();
        }finally {
            System.out.println("num值:"+jedis.get("num"));
            JedisPoolUtil.release(jedisPoolInstance,jedis);
        }

    }
    
    --结果--
    num值:12
  • 配置总结: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_BLOC:则表示阻塞住,或者达到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
下一篇:redis学习-33-SpringBoot整合redis
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值