栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

03-Java中操作redis

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

03-Java中操作redis

文章目录
    • 准备工作
      • 创建工程
      • 添加项目依赖
    • Jedis的应用
      • 简介
      • 准备工作
    • 快速入门实现
      • 基础类型操作
      • 连接池JedisPool应用
    • RedisTemplate应用
      • 简介
      • 准备工作
      • 快速入门实现
        • StringRedisTemplate 应用
        • RedisTemplate 应用
        • 定制RedisTemplate对象(拓展)
    • 项目工程实践
      • 单点登陆
        • 业务描述
        • 关键代码实现
      • 投票系统
        • 业务描述
        • 关键代码实现
      • 秒杀队列
        • 业务描述
        • 关键代码实现
      • 分布式id
        • 业务描述
        • 关键代码实现
      • 购物车简易实现
        • 业务描述
        • 关键代码实现
    • 总结(Summary)

准备工作 创建工程

创建maven父工程,例如03-sca-redis,并在此工程下创建两个子工程,一个为sca-jedis,一个为sca-tempate,例如:

添加项目依赖

sca-jedis 工程依赖


    redis.clients
    jedis
    3.5.2



    junit
    junit
    4.12
    test



    com.google.code.gson
    gson
    2.8.6

添加sca-template工程依赖


        
            
                org.springframework.boot
                spring-boot-dependencies
                2.3.2.RELEASE
                import
                pom
            
        
    
    
    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.boot
            spring-boot-starter-data-redis
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    
Jedis的应用 简介

Jedis是Java中操作redis的一个客户端,类似通过jdbc访问mysql数据库。

准备工作

第一步:从redis.io官方下载对应版本的redis.conf文件,地址如下:

https://redis.io/topics/config/

第二步:停止redis并删除挂载目录下(/usr/local/docker/redis01/conf)的redis.conf配置文件.-> (通过 docker inspect redis01 查看挂载目录)
第三步:将下载的redis.conf文件拷贝到redis挂载目录(/usr/local/docker/redis01/conf)
第四步:基于vim打开redis.conf文件,
注释 bind 127.0.0.1这一行,

并修改protected-mode的值修改为no或者直接注释掉.

第五步:重启redis服务,并检查启动日志(docker logs 容器id)

快速入门实现

在Jedis工程中定义单元测试类,在类中定义单元测试方法:

基础类型操作

在项目的src/test/java目录创建单元测类,例如:

package com.jt;

import com.google.gson.Gson;
import org.junit.Test;
import redis.clients.jedis.Jedis;

import java.util.*;
import java.util.concurrent.TimeUnit;

public class JedisTests {

    
    @Test
    public void testGetConnection(){//JDK8
        Jedis jedis = new Jedis("192.168.126.129",6379);
        //jedis.auth("123456");假如在redis.conf中设置了密码,还需执行这条语句
        String ping = jedis.ping();
        System.out.println(ping);///PONG
    }

    
    @Test
    public void testStringOper() throws InterruptedException {
        //1.建立链接
        Jedis jedis = new Jedis("192.168.126.129",6379);

        //2.向redis中存储数据
        jedis.set("id", "1");
        jedis.set("name", "Toney");
        jedis.set("token", UUID.randomUUID().toString());
        jedis.expire("token", 2);

        //3.更新redis中指定数据
        jedis.set("id", "100");
        jedis.incr("id");
        jedis.incrBy("id", 2);
        jedis.decr("id");

        //4.删除redis中指定数据
        jedis.del("name");

        //5.查看redis中的数据
        String id = jedis.get("id");
        String name = jedis.get("name");
        String token = jedis.get("token");
        Long tokenStrLen = jedis.strlen("token");

        System.out.println("id = "+id);
        System.out.println("name = "+name);
        System.out.println("token = "+token);
        System.out.println("token.length = "+tokenStrLen);
        //Thread.sleep(2000);
        //TimeUnit是Java中枚举类型,SECONDS为枚举类型的实例,sleep底层会调用Thread.sleep()方法
        //TimeUnit.SECONDS.sleep(2);//休眠2秒
        TimeUnit.SECONDS.sleep(2);
        token = jedis.get("token");
        System.out.println("token = "+token);

        //6.释放资源
        jedis.close();
    }

    
    @Test
    public void testHashOper01(){
        //1.建立链接
        Jedis jedis = new Jedis("192.168.126.129",6379);

        //2.向redis中存储数据
        jedis.hset("user","id","100");
        jedis.hset("user", "name","jack");
        jedis.hset("user", "mobile","111111");

        //3.更新redis中指定数据
        jedis.hset("user", "id","101");

        //4.删除redis中指定数据
        jedis.hdel("user", "mobile");

        //5.查看redis中的数据
        String id = jedis.hget("user", "id");
        System.out.println("user id = "+id);
        Map user = jedis.hgetAll("user");
        System.out.println("user = "+user);

        //6.释放资源
        jedis.close();
    }

    
    @Test
    public void testStringJsonOper(){
        //1.建立链接
        Jedis jedis = new Jedis("192.168.126.129",6379);

        //2.将对象转换为json字符串
        Map map = new HashMap<>();
        map.put("id", "101");
        map.put("name", "tony");
        Gson gson = new Gson();//Google公司提供
        String jsonStr = gson.toJson(map);//将map转换为json串
        System.out.println("jsonStr = "+jsonStr);

        //3.将json字符串存储到redis
        jedis.set("member",jsonStr);

        //4.取出member对象的值
        String member = jedis.get("member");
        System.out.println("redis.member = "+member);

        //5.将json字符串转换成map对象
        map = gson.fromJson(member, Map.class);
        System.out.println(map);

        //6.释放资源
        jedis.close();
    }

    
    @Test
    public void testHashOper02() {
        //1.建立链接
        Jedis jedis = new Jedis("192.168.126.129", 6379);

        //2.存储一个map对象
        Map map = new HashMap<>();
        map.put("x", "100");
        map.put("y", "200");
        jedis.hset("point", map);

        //3.读取一个map对象
        Map point = jedis.hgetAll("point");
        System.out.println(point);//{x=100, y=200}

        //4.释放资源
        jedis.close();
    }

    
    @Test
    public void testListOper01(){
        //1.建立链接
        Jedis jedis = new Jedis("192.168.126.129", 6379);

        //2.存储数据(list集合有顺序,允许重复)
        jedis.lpush("lst1", "A","B","C","C");

        //3.修改数据
        //3.1 首先获取要修改的元素的下标
        Long index = jedis.lpos("lst1", "A");
        //3.2 基于下标,修改元素内容
        jedis.lset("lst1", index,"D");

        //4.删除数据
        jedis.rpop("lst1",20);

        //5.查询数据
        List lst1 = jedis.lrange("lst1", 0, -1);
        System.out.println(lst1);

        //6.释放资源
        jedis.close();
    }

    
    @Test
    public void testListOper02() {
        //1.建立链接
        Jedis jedis = new Jedis("192.168.126.129", 6379);

        //2.存储数据(list集合有顺序,允许重复)
        jedis.lpush("lst2", "A","B","C");

        //3.基于阻塞式方式获取数据
        jedis.brpop(50, "lst2");
        jedis.brpop(50, "lst2");
        List lst1 = jedis.brpop(50, "lst2");
        System.out.println(lst1);//[lst2, C] 输入的内容为key和pop处的值
        jedis.brpop(50, "lst2");

        //4.释放资源
        jedis.close();
    }

    @Test
    public void testSetOper01(){
        //1.建立链接
        Jedis jedis=new Jedis("192.168.126.129",6379);

        //2.存储数据(Set集合没有顺序,不允许重复)
        jedis.sadd("set1", "A","A","B","C","D");

        //3.修改数据
        //4.删除数据
        //jedis.spop("set1");
        jedis.srem("set1", "B");

        //5.查询数据
        Set set1 = jedis.smembers("set1");
        System.out.println(set1);
        Long cards = jedis.scard("set1");
        System.out.println(cards);

        //5.释放资源
        jedis.close();
    }
}
连接池JedisPool应用

我们直接基于Jedis访问redis时,每次获取连接,释放连接会带来很大的性能开销,可以借助Jedis连接池,重用创建好的连接,来提高其性能,简易应用方式如下:

package com.jt;

import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;


public class JedisPoolTests {

    @Test
    public void testJedisPool(){
        //1.构建jedis连接池(JedisPool对象)
        //1.1定义连接池配置
        JedisPoolConfig config=new JedisPoolConfig();
        config.setMaxTotal(16);//最大连接数,默认为8
        config.setMaxIdle(60);//最大空闲时间(连接后续不用了,超出一定空闲时间要释放)
        //config.setxxxx

        //1.2定义连接的url和端口
        String host="192.168.126.129";
        int port=6379;
        //1.3创建连接池
        JedisPool jedisPool=
                new JedisPool(config,host,port);
        //2.从池中获取连接(jedis对象)
        Jedis resource = jedisPool.getResource();
        //3.执行redis操作
        resource.set("pool", "JedisPool");
        String pool = resource.get("pool");
        System.out.println(pool);
        //4.释放资源(不是关,而是将连接还回池中)
        resource.close();
        //5.关闭池(一般服务停止时关)
        //jedisPool.close();
    }
}
RedisTemplate应用 简介

RedisTemplate为SpringBoot工程中操作redis数据库的一个Java对象,此对象封装了对redis的一些基本操作。

准备工作

第一步:创建工程配置文件application.yml,其内容如下:

spring:
  redis:
    host: 192.168.64.129  #写自己的ip
    port: 6379

第二步:创建工程启动类,例如:

package com.jt;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class RedisApplication {
    public static void main(String[] args) {
        SpringApplication.run(RedisApplication.class,args);
    }
}
快速入门实现 StringRedisTemplate 应用

StringRedisTemplate 是一个专门用于操作redis字符串类型数据的一个对象,其应用方式如下:

 
RedisTemplate 应用 

RedisTemplate是一个专门用于实现对远端redis中复杂数据的操作的对应,应用案例如下:

 
定制RedisTemplate对象(拓展) 

对于系统默认的RedisTemplate默认采用的是JDK的序列化机制,假如我们不希望实用JDK的序列化,可以采用的定制RedisTemplate,并采用自己指定的的序列化方式,例如:

 
项目工程实践 
单点登陆 
业务描述 

在分布式系统中,通过会有多个服务,我们登录了一个服务以后,再访问其它服务时,不想再登录,就需要有一套单独的认证系统,我们通常会称之为单点登录系统,在这套系统中提供一个认证服务器,服务完成用户身份认证,在一些中小型分布式系统中中,我们通常会借助redis存储用户的认证信息,例如:

关键代码实现

SSODemo01.java

package com.jt.redis;

import redis.clients.jedis.Jedis;
import java.util.UUID;


public class SSODemo01 {
    
    public static String doLogin(String username,String password){
        //1.执行用户身份校验
        if(!"jack".equals(username))//将来这个jack来自数据库
            throw new IllegalArgumentException("这个用户不存在");
        //2.用户存在并且密码正确,表示用户是系统的合法用户
        if(!"123456".equals(password))
            throw new IllegalArgumentException("密码不正确");
        //3.将合法用户信息存储到redis
        Jedis jedis = new Jedis("192.168.126.129", 6379);
        String token = UUID.randomUUID().toString();
        jedis.set(token,username);
        jedis.expire(token, 2);
        jedis.close();
        return token;//token
    }
    
    
    public static Object doGetResource(String token){
        //1.检查用户是否已经登录
        if(token == null || "".equals(token))
            throw new IllegalArgumentException("请先登录");
        Jedis jedis = new Jedis("192.168.126.129", 6379);
        String username = jedis.get(token);
        jedis.close();
        //2.假如没有登录,则提示先登录
        if(username == null)
            throw new RuntimeException("登录超时或token无效,请重新登录");
        //3.已登录则可以访问资源
        System.out.println("继续访问资源");
        //.....
        return "the resource of user";
    }
    
    //假设这里的main方法为客户端
    public static void main(String[] args) throws InterruptedException {
        String token = null;
        //第一次访问资源
        // doGetResource(token);
        //执行登录操作(将来认证要在认证中心实现)
        token = doLogin("jack", "123456");
        //第二次访问资源
        doGetResource(token);
    }
}

SSODemo02.java

package com.jt.redis;

import redis.clients.jedis.Jedis;
import java.util.Map;
import java.util.UUID;


public class SSODemo02 {
    private static String token;

    
    public static String doLogin(String username,String password){
        //1.执行用户身份校验
        if(!"jack".equals(username))//将来这个jack来自数据库
            throw new IllegalArgumentException("这个用户不存在");
        //2.用户存在并且密码正确,表示用户是系统的合法用户
        if(!"123456".equals(password))
            throw new IllegalArgumentException("密码不正确");
        //3.将合法用户信息存储到redis
        Jedis jedis = new Jedis("192.168.126.129", 6379);
        String token = UUID.randomUUID().toString();
        jedis.hset(token,"username",username);
        jedis.hset(token,"status","1");
        //...
        jedis.expire(token, 2);
        jedis.close();
        return token;//token
    }

    
    public static Object doGetResource(String token){
        //1.检查用户是否已经登录
        if(token == null || "".equals(token))
            throw new IllegalArgumentException("请先登录");
        Jedis jedis = new Jedis("192.168.126.129", 6379);
        Map map = jedis.hgetAll(token);
        jedis.close();
        //2.假如没有登录,则提示先登录
        System.out.println("map = "+map);//map = {username=jack, status=1}
        if(map.isEmpty())
            throw new RuntimeException("登录超时或token无效,请重新登录");
        //3.已登录则可以访问资源
        System.out.println("继续访问资源");
        //.....
        return "the resource of user";
    }

    //假设这里的main方法为客户端
    public static void main(String[] args) throws InterruptedException {
        //第一次访问资源
        // doGetResource(token);
        //执行登录操作(将来认证要在认证中心实现)
        token = doLogin("jack", "123456");
        //第二次访问资源
        //Thread.sleep(2000);
        doGetResource(token);
    }
}
投票系统 业务描述

在很多系统中设计中,都会有一个活动设计,开启一个活动之前,可以对这个活动的支持力度先进行一个调查,例如基于这个活动设计一个投票系统,例如:

关键代码实现
package com.jt.redis;

import redis.clients.jedis.Jedis;
import java.util.Set;


public class VoteDemo01 {
    static final String IP = "192.168.126.129";
    static final int PORT = 6379;

    
    public static Boolean isVote(String activityId,String userId){
        //1.创建Jedis对象
        Jedis jedis = new Jedis(IP,PORT);
        //2.检查是否投票
        Boolean flag = jedis.sismember(activityId, userId);
        //3.释放资源
        jedis.close();
        //4.返回结果
        return flag;
    }

    
    public static void doVote(String activityId,String userId){
        //1.创建Jedis对象
        Jedis jedis = new Jedis(IP,PORT);
        //2.执行投票
        jedis.sadd(activityId, userId);
        //3.释放资源
        jedis.close();
    }

    
    public static Long doGetVote(String activityId){
        //1.创建Jedis对象
        Jedis jedis = new Jedis(IP,PORT);
        //2.查看活动的投票数
        Long count = jedis.scard(activityId);
        //3.释放资源
        jedis.close();
        //4.返回投票数量
        return count;
    }

    
    public static Set doGetUser(String activityId){
        //1.创建Jedis对象
        Jedis jedis = new Jedis(IP,PORT);
        //2.查看活动的投票数
        Set smembers = jedis.smembers(activityId);
        //3.释放资源
        jedis.close();
        //4.返回投票数量
        return smembers;
    }

    public static void main(String[] args) {
        //1.定义活动id
        String activityId = "1001";
        String user1 = "301";
        String user2 = "302";
        //2.进行投票
        doVote(activityId, user1);
        //3.进行投票检查
        Boolean flag = isVote(activityId, user1);
        Boolean flag1 = isVote(activityId, user2);
        //4.获取投票的总数
        Long aLong = doGetVote(activityId);
        System.out.println(activityId + " 的总投票数为 " + aLong);
        //5.获取参与投票的用户
        Set users = doGetUser(activityId);
        System.out.println(users);
        //6.检查用户是否投过票
        System.out.println(user1 + ":" + (flag?"已投过票":"还没投票"));
        System.out.println(user2 + ":" + (flag1?"已投过票":"还没投票"));
    }
}
秒杀队列 业务描述

在设计一个秒杀或抢购系统时,为了提高系统的响应速度,通常会将用户的秒杀或抢购请求先存储到一个redis队列,这里我们就基于redis实现一个先进先出队列,例如:

关键代码实现
package com.jt.redis;

import redis.clients.jedis.Jedis;
import java.util.List;


public class SecondsKillDemo01 {

    
    public static void enque(String request){
        Jedis jedis = new Jedis("192.168.126.129", 6379);
        //jedis.auth("123456");若有密码,则写此语句
        jedis.lpush("queue-1",request);
        jedis.close();
    }

    
    public static String deque(){
        Jedis jedis = new Jedis("192.168.126.129", 6379);

        //非阻塞式取数据
        //return jedis.rpop("queue-1");
        //阻塞式取数据
        List list = jedis.brpop(60, "queue-1");
        jedis.close();
        return list!=null?list.get(1):null;//0为key,1为value
    }

    public static void main(String[] args) {
        //1.构建生产者对象(购买商品的用户)
        Thread t1 = new Thread(){
            @Override
            public void run() {
                int i = 1;
                for(;;){
                    enque("request-1"+i++);
                    try { Thread.sleep(1000);
                    }catch (Exception e){}
                }
            }
        };

        //2.构建消费者对象(处理请求的对象)
        Thread t2 = new Thread(){
            @Override
            public void run() {
                for(;;){
                    String request = deque();
                    if(request == null) continue;
                    System.out.println("process"+request);
                }
            }
        };

        //3.开启抢购活动
        t1.start();
        t2.start();
    }
}
分布式id 业务描述

在分布式系统中,数据量将越来越大时,就需要对数据进行分表操作,但是,分表后,每个表中的数据都会按自己的节奏进行自增,很有可能出现ID冲突。这时就需要一个单独的机制来负责生成唯一ID,生成出来的ID也可以叫做 分布式ID,这里我们借助redis实现一个简易的分布式id进行实现,当然还有一些第三方的系统,可以帮你生成这样的id,可以自己进行拓展学习.

关键代码实现
package com.jt.redis;

import redis.clients.jedis.Jedis;


public class IdGenerator {
    
    public static Long getId(){
        Jedis jedis=new Jedis("192.168.126.129", 6379);
        //jedis.auth("123456");//密码
        //incr方法用于对指定key的值进行递增,假如key不存在则创建
        long id = jedis.incr("incrementId");
        jedis.close();
        return id;
    }
    public static void main(String[] args) {
        for(int i=0;i<10;i++){
            new Thread(){
                @Override
                public void run() {
                    System.out.println(IdGenerator.getId());
                }
            }.start();
        }
    }
}
购物车简易实现 业务描述

简易购物车业务设计如图所示:

基础指令操作,例如:

1)向购物车添加商品
hset cart:101 2001 1
hset cart:101 2002 1
hset cart:101 2003 2
2)查看购物车商品
hgetall cart:101
3)删除购物车商品
hdel cart:101 2003
4)改变购物车某个商品的购买数量
hincrby cart:101 2002 2
hincrby cart:101 2002 -2
关键代码实现
package com.jt.redis;

import redis.clients.jedis.Jedis;

import java.util.Map;


public class CartDemo01 {
    static final String IP = "192.168.126.129";
    static final int PORT = 6379;

    
    public static void doAddCart(String userId,String productId,int num){
        //1.创建Jedis对象
        Jedis jedis = new Jedis(IP,PORT);
        //2.基于hash结构存储商品信息
        //hincrBy这个函数在key不存在时会自动创建key
        jedis.hincrBy("cart:"+userId, productId, num);
        //3.释放资源
        jedis.close();
    }

    
    public static Map doViewCart(String userId){
        //1.创建Jedis对象
        Jedis jedis = new Jedis(IP,PORT);
        //2.产看购物车信息
        Map cart = jedis.hgetAll("cart:" + userId);
        //3.释放资源
        jedis.close();
        //4.返回购物车商品信息
        return cart;
    }

    
    public static void doClearCart(String userId,String... productIds){
        //1.创建Jedis对象
        Jedis jedis = new Jedis(IP,PORT);
        //2.删除指定商品
        jedis.hdel("cart:"+userId,productIds);
        //3.释放资源
        jedis.close();
    }

    public static void main(String args[]){
        String userId = "101";
        //1.购买商品时,将商品信息添加到购物车
        doAddCart(userId,"2001",1);
        doAddCart(userId,"2002",1);
        doAddCart(userId,"2003",1);
        //2.修改购物车商品的数量
        doAddCart(userId, "2002", 1);
        doAddCart(userId, "2003", 2);
        //3.查看购物车商品信息
        Map cart = doViewCart(userId);
        System.out.println(cart);
        //4.清空购物车
        doClearCart(userId,"2001","2002","2003");
        cart = doViewCart(userId);
        System.out.println(cart);
    }
}
总结(Summary)

本章节主要对Java中操作redis数据库的方式及API应用进行了分析和实践,具体方法的理解可以在实践中基于结果进行分析,逐步进行强化记忆。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/310988.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号