关于redis实际项目中的多种使用(个人总结)

工作了一段时间,发现很多项目都使用了nosql非关系型数据库redis。可以说目前市场上的项目基本上都会使用缓存,而本小白因为才入坑,一开始做的几个项目虽然都使用了redis但都用的稀里糊涂,只是在开发中使用大佬们封装好的redisUtil工具类,每次代码需要存redis或者取的时候就直接调用。。。真是知其然不知其所以然。。。
故此回过头研究一下具体是怎么存入redis的

@Api(value = "手持pos机用户controller")
@Controller
@RequestMapping("/handheldPosLogin")
public class HandheldPosLoginController extends BaseController {

    @Autowired
    private LoginClient loginClient;
    @Autowired
    private RedisUtil redisUtil;

    private static final Integer SESSION_OUT_TIME = 60 * 60 * 1000;


    @ApiOperation(value = "用户登录", notes = "用户登录")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "loginRequest", value = "用户登录请求类", required = true, dataType = "LoginRequest")
    })
    @RequestMapping(value = "/doLogin", method = RequestMethod.POST)
    @ResponseBody
    public BaseResult doLogin(@Valid @RequestBody LoginRequest loginRequest) {
        logger.info("用户登录");
        BaseResult baseResult = loginClient.doLogin(loginRequest);
        String token = "";
        if (baseResult.getCode() == SystemMsgBase.SUCCESS_COMMON_CODE) {
            token = CommonUtils.get32UUID();
            Map<String, Object> tStaff = (HashMap) baseResult.getData();
            UserSessionTemplate template = new UserSessionTemplate();
            template.setUserId((String) tStaff.get(Commonconstants.GUID));
            template.setShopId((String) tStaff.get(Commonconstants.USER_SHOP_GUID));
            template.settStaff((TStaff) JavaBeanUtil.map2Object(tStaff, TStaff.class));
            template.setOutTime(System.currentTimeMillis());
            template.setToken(token);
//            SessionManager.addSession(token, template);
            redisUtil.set(token, JSON.toJSONString(template),SESSION_OUT_TIME);
            return BaseResult.ok(token);
        }else{
            return BaseResult.fail(baseResult.getCode(),baseResult.getMessage());
        }

    }

首先这里是之前的一个项目,这一块是controller层的一个POS端的用户登入。很明显是用户点击登入需要输入用户的账号密码然后在这里验证,成功会返回一个token并将此token存入缓存redis中。

	redisUtil.set(token, JSON.toJSONString(template),SESSION_OUT_TIME);

这里使用了项目的redis工具类set方法进行存键操作,把生成的token、用户登入信息和缓存有效时间这三个参数代入调用了存缓存方法。然后我点进去看一下这个方法

 /**
     * 普通缓存放入并设置时间
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
     * @return true成功 false 失败
     */
    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }



 /**
     * 普通缓存放入
     *
     * @param key   键
     * @param value 值
     * @return true成功 false失败
     */
    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }

这里看到在工具类里面使用了redisTemplate
在这里插入图片描述

	  redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);

这里key(键)的值就是token,value的值就是用户信息,time就是缓存有效时间,TimeUnit.SECONDS是存入的时间。
很明显这里redis存入的类型是string也是一般项目最长用的缓存类型。

这里讲一下redis存缓存的各种方式

1、保存和读取String(最常用的)

System.out.println("缓存正在设置。。。。。。。。。");  
redisTemplate.opsForValue().set("key1","value1");  
redisTemplate.opsForValue().set("key2","value2");  
redisTemplate.opsForValue().set("key3","value3");  
redisTemplate.opsForValue().set("key4","value4");  
System.out.println("缓存已经设置完毕。。。。。。。");  
String result1=redisTemplate.opsForValue().get("key1").toString();  
String result2=redisTemplate.opsForValue().get("key2").toString();  
String result3=redisTemplate.opsForValue().get("key3").toString();  
System.out.println("缓存结果为:result:"+result1+"  "+result2+"   "+result3);  

运行结果:

resultList1:value1 value2 value3

2、保存和读取Set:

代码示例:

SetOperations<String, String> set = redisTemplate.opsForSet();
		set.add("set1","22");  
		set.add("set1","33");  
		set.add("set1","44");  
		Set<String> resultSet =redisTemplate.opsForSet().members("set1");  
		System.out.println("resultSet:"+resultSet); 

运行结果为:

resultSet:[[set3, set2, set1]] jedis

3、Hash结构,保存和读取map:

示例代码:

Map<String,String> map=new HashMap<String,String>();  
map.put("key1","value1");  
map.put("key2","value2");  
map.put("key3","value3");  
map.put("key4","value4");  
map.put("key5","value5");  
redisTemplate.opsForHash().putAll("map1",map);  
Map<String,String> resultMap= redisTemplate.opsForHash().entries("map1");  
List<String>reslutMapList=redisTemplate.opsForHash().values("map1");  
Set<String>resultMapSet=redisTemplate.opsForHash().keys("map1");  
String value=(String)redisTemplate.opsForHash().get("map1","key1");  
System.out.println("value:"+value);  
System.out.println("resultMapSet:"+resultMapSet);  
System.out.println("resultMap:"+resultMap);  
System.out.println("resulreslutMapListtMap:"+reslutMapList); 

运行结果为:

value:value1

resultMapSet:[key1, key2, key5, key3, key4]

resultMap:{key3=value3, key2=value2, key1=value1, key5=value5, key4=value4}

resulreslutMapListtMap:[value1, value2, value5, value3, value4]

4、保存和读取list

示例代码:

List<String> list1=new ArrayList<String>();  
 list1.add("a1");  
list1.add("a2");  
 list1.add("a3");  
 
 List<String> list2=new ArrayList<String>();  
  list2.add("b1");  
 list2.add("b2");  
 list2.add("b3");  
redisTemplate.opsForList().leftPush("listkey1",list1);  
redisTemplate.opsForList().rightPush("listkey2",list2);  
List<String> resultList1=(List<String>)redisTemplate.opsForList().leftPop("listkey1");  
 List<String> resultList2=(List<String>)redisTemplate.opsForList().rightPop("listkey2");  
System.out.println("resultList1:"+resultList1);  
System.out.println("resultList2:"+resultList2);  

运行结果:

resultList1:[a1, a2, a3]

resultList2:[b1, b2, b3]

这里需要解释一下:不管是leftPush还是rightPush都可以用leftPop或者rightPoP任意一种获取到其中的值,不过就是获取的遍历方向不一样。有学过数据结构的人都知道里面循环链表是可以前后遍历的,就和这里的场景是一样的。如果还有不懂的话可以去看看这部分的源代码,其实就是遍历方向不同,所以效率也不同。所以最好leftPush用leftPoP遍历,rightPush用rightPoP遍历

此处感谢博客原文链接:https://blog.csdn.net/lichuangcsdn/article/details/80866182

由于这个项目只有这里使用到了缓存所以而且也特别简单,就是存key,value以及按照对应的取就没了。。好了来看下一个
另一个项目里面的redis存缓存工具类,使用的是jedisPool,关于jedis和jedisPool看一下大佬博客的介绍

1、Jedis介绍
Redis不仅是使用命令来操作,现在基本上主流的语言都有客户端支持,比如java、C、C#、C++、php、Node.js、Go等。在官方网站里列一些Java的客户端,有Jedis、Redisson、Jredis、JDBC-Redis、等其中官方推荐使用Jedis和Redisson。 在企业中用的最多的就是Jedis。Jedis提供了完整Redis命令,而Redisson有更多分布式的容器实现。

2、添加Maven依赖

<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
  <version>3.0.1</version>
</dependency>

3、单例连接

通过创建jedis对象连接jedis服务

 Jedis jedis = new Jedis("127.0.0.1", 6379);
 jedis.auth("admin");
 //ping通显示PONG
 System.out.println(jedis.ping());//去ping我们redis的主机所在ip和端口

4、使用JedisPool连接池

单一Jedis实例不是线程安全的, JedisPool是一个线程安全的网络连接池。可以用JedisPool创建一些可靠Jedis实例,可以从池中拿到Jedis的实例。这种方式可以解决那些问题并且会实现高效的性能。

原文链接:https://blog.csdn.net/bobozai86/article/details/89715025

看完大佬的博客知道Jedis提供了完整Redis命令,用JedisPool创建一些可靠Jedis实例,可以从池中拿到Jedis的实例。好了,看一下这个项目中jedisPool是具体怎么使用的,首先POM.XML中导入jedis

然后是在redis工具类这里注入了jedisPool对象
在这里插入图片描述

里面的set方法

  /**
 * <p>
 * 向redis存入key和value,并释放连接资源
 * </p>
 * <p>
 * 如果key已经存在 则覆盖
 * </p>
 *
 * @param key
 * @param value
 * @param indexdb 选择redis库 0-15
 * @return 成功 返回OK 失败返回 0
 */
public String set(String key, String value,int indexdb) {
    Jedis jedis = null;
    try {
        jedis = jedisPool.getResource();
        jedis.select(indexdb);
        return jedis.set(key, value);
    } catch (Exception e) {

        log.error(e.getMessage());
        return "0";
    } finally {
        returnResource(jedisPool, jedis);
    }
}

这里也实现了存入redis,好像和RedisTemplate差不多,那么他们的差别是什么呢?
答:RedisTemplate是SpringDataRedis中对JedisApi的高度封装。而Jedis是Redis官方推荐的面向Java的操作Redis的客户端,可以用JedisPool来获得连接进行get、set、del等操作相对简单

看来实际项目中如果业务不复杂只是单纯的存取更新和删除key、value的话使用都蛮简单的,存储类型也无非是设定key然后以string存储较多。

我们自己再测试练一下:
自己写一个redis工具类,里面建立jedisPool连接池

public class JedisPoolUtil {
    /**
     * host
     */
    private static String ADDR = "127.0.0.1";
    /**
     * password
     */
    private static String AUTH = "admin";
    /**
     * port
     */
    private static int PORT = 6379;

private static JedisPool jedisPool = null;
private static int TIMEOUT = 10000;
/**
 * 等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
 */
private static int MAX_WAIT = 10000;
/**
 * 在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
 */
private static boolean TEST_ON_BORROW = true;
/**
 * 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
 */
private static int MAX_IDLE = 200;


static {
    try {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxIdle(MAX_IDLE);
        config.setTestOnBorrow(TEST_ON_BORROW);
        config.setMaxWaitMillis(MAX_WAIT);
        jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static Jedis getJedis() {
    if (jedisPool != null) {
        Jedis jedis = jedisPool.getResource();
        return jedis;
    }
    return null;
}

public static void close(Jedis jedis) {
    if (jedis != null) {
        jedis.close();
    }
  }
}

进行代码测试

public class JedisTest {

public static void main(String[] args) {
//        testString();
//        testMap();
//        testList();
//        testSet();
        testSortSet();
    }

public static Jedis connect() {
    //从redis 连接池中获取
    Jedis jedis = JedisPoolUtil.getJedis();
    return jedis;
}

/**
 * 操作string类型的key
 * string 是最基本的类型,而且 string 类型是二进制安全的。意思是 redis 的 string 可以 包含任何数据。
 * 比如 jpg 图片或者序列化的对象。从内部实现来看其实 string 可以看作 byte数组,最大上限是 1G 字节
 */
public static void testString() {
    Jedis jedis = connect();
    jedis.set("name", "abel");
    // set 多个key and value
    jedis.mset("name", "abel", "age", "23", "qq", "123244232");
    //age  + 1
    jedis.incr("age");
    System.out.println(jedis.get("name"));
    // delete key
    jedis.del("name");
    jedis.close();
}

/**
 * 操作map
 * hash 是一个 string 类型的 field 和 value 的映射表。添加,删除操作都是 O(1)(平均)。
 * hash 特别适合用于存储对象。相对于将对象的每个字段存成单个 string 类型。将一个对象存储在 hash 类型中会占用更少的内存,并且可以更方便的存取整个对象。
 */
public static void testMap() {
    Map<String, String> map = new HashMap<>();
    map.put("address", "上海");
    map.put("name", "abel");
    map.put("age", "23");
    Jedis jedis = connect();
    jedis.hmset("user", map);

    // 从map 中取出 value
    // 第一个参数是存入redis中map对象的key,后面跟的是放入map中的对象的key,后面的key可以跟多个,是可变
    List<String> getmap = jedis.hmget("user", "address");
    System.out.println(getmap);
    List<String> getmap2 = jedis.hmget("user", "address", "age");
    System.out.println(getmap2);

    //删除map中的某个键值
    jedis.hdel("user", "age");

    System.out.println(jedis.hlen("user")); //返回key为user的键中存放的值的个数2

    System.out.println(jedis.exists("user"));//是否存在key为user的记录 返回true
    System.out.println("all keys : " + jedis.hkeys("user"));//返回map对象中的所有key
    System.out.println("all values : " + jedis.hvals("user"));//返回map对象中的所有value

    //获取 user 中的所有key
    Set<String> keys = jedis.hkeys("user");
    keys.stream().forEach(x -> System.out.println("key: " + x));
}

/**
 * list 链表
 * list 是一个链表结构,可以理解为一个每个子元素都是 string 类型的双向链表
 */
private static void testList() {
    Jedis jedis = connect();
    //移除 lists 中所有的内容
    jedis.del("lists");

    // 向key lists 链表头部添加字符串元素
    jedis.lpush("lists", "abel1");
    jedis.lpush("lists", "abel2");
    jedis.lpush("lists", "abel3");
    // 向key lists 链表尾部添加字符串元素
    jedis.rpush("lists", "abel4");
    jedis.rpush("lists", "abel5");

    //获取lists 的长度
    System.out.println(jedis.llen("lists"));
    //按顺序输出链表中所有元素
    System.out.println(jedis.lrange("lists", 0, -1));
    //在abel4 前插入 abelLinsert
    jedis.linsert("lists", BinaryClient.LIST_POSITION.BEFORE, "abel4", "abelLinsert");
    System.out.println(jedis.lrange("lists", 0, -1));

    //修改列表中指定下标2 的值  为abelLset
    jedis.lset("lists", 2, "abelLset");
    System.out.println(jedis.lrange("lists", 0, -1));


    //插入两个 abel2 为了后面的删除
    jedis.lpush("lists", "abel2");
    jedis.lpush("lists", "abel2");
    // 从 lists 中删除 3 个 value = abel2 的元素 , 可以不连续
    // 当删除 count = 0 个 时则删除全部 value = abel2 的元素
    jedis.lrem("lists", 0, "abel2");
    System.out.println(jedis.lrange("lists", 0, -1));

}

/**
 * 
 * set 是无序集合,最大可以包含(2 的 32 次方-1)40多亿个元素。
 * set 的是通过 hash table 实现的, 所以添加,删除,查找的复杂度都是 O(1)。hash table 会随着添加或者删除自动的调整大小。
 */
public static void testSet() {
    Jedis jedis = connect();
    jedis.sadd("person", "abel1");
    jedis.sadd("person", "abel2");
    jedis.sadd("person", "abel3");
    jedis.sadd("person", "abel4");
    jedis.sadd("person", "abel4");

    //获取所有加入的value
    System.out.println(jedis.smembers("person"));
    // 从 person 中 移除 abel4
    jedis.srem("person", "abel4");
    //获取所有加入的value
    System.out.println("values: " + jedis.smembers("person"));
    //判断 abels 是否是 person 集合的元素
    System.out.println(jedis.sismember("person", "abels"));
    //返回集合中的一个随机元素
    System.out.println(jedis.srandmember("person"));
    //返回集合的元素个数
    System.out.println(jedis.scard("person"));
}

/**
 * sorted 
 * sorted set 是有序集合,它在 set 的基础上增加了一个顺序属性,这一属性在添加修 改元素的时候可以指定,每次指定后,会自动重新按新的值调整顺序。
 * 可以理解了有两列的 mysql 表,一列存 value,一列存顺序。
 * <p>
 * sort set和set类型一样,也是string类型元素的集合,也没有重复的元素,不同的是sort set每个元素都会关联一个权,
 * 通过权值可以有序的获取集合中的元素添加,删除,查找的复杂度都是O(1)
 */
public static void testSortSet() {
    Jedis jedis = connect();
    System.out.println(jedis.flushDB());
    jedis.zadd("sortKey", 300, "abel");
    jedis.zadd("sortKey", 20, "mysql");
    jedis.zadd("sortKey", 40, "redis");

    // 按权值从小到大排序
    System.out.println(jedis.zrange("sortKey", 0, -1));
    // 按权值从大到小排序
    System.out.println(jedis.zrevrange("sortKey", 0, -1));

    // 元素个数
    System.out.println("元素个数:" + jedis.zcard("sortKey"));
    // 元素abel 的 下标
    System.out.println("元素xxx 的 下标:" + jedis.zscore("sortKey", "abel"));

    // 删除元素 abel
	// jedis.zrem("sortKey", "abel");

    //权值 0-100的总数
    System.out.println("0-100 的总数: " + jedis.zcount("sortKey", 0, 100));
    //给元素 redis 的 权值 + 50
    System.out.println("给元素的 权值  + 50: " + jedis.zincrby("sortKey", 50, "redis"));
    //权值在0-100的值
    System.out.println("权值在0-100的值: " + jedis.zrangeByScore("sortKey", 0, 100));
    //返回 mysql 的权值的排名,从0开始计数
    System.out.println(jedis.zrank("sortKey", "mysql"));
    // 输出整个集合值
    System.out.println("输出整个集合值: " + jedis.zrange("sortKey", 0, -1));
}

}

此处感谢博客,原文链接:https://blog.csdn.net/bobozai86/article/details/89715025

  • 6
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值