新手小白入门redis

一、简介

Redis是一个key-value存储系统,是nosql一个分布式缓存数据库。Redis官方是不支持windows平台的,windows版本是由微软自己建立的分支,基于官方的Redis源码上进行编译、发布、维护的,所以windows平台的Redis版本要略低于官方版本。
Redis 相关参考网址如下所示:

Bootnb 相关:https://www.runoob.com/redis/redis-tutorial.html
Redis 官网:https://redis.io/
源码地址:https://github.com/redis/redis
Redis 在线测试:http://try.redis.io/
Redis 命令参考:http://doc.redisfans.com/

二、redis初始化操作

docker下搭建redis数据库点这里>>>
进入redis容器登录redis

 docker exec -it redis01 redis-cli -h 127.0.0.1 -p 6379  #如果设置了密码后面加参数 -a  密码

查看当前redis节点的详细配置信息

127.0.0.1:6379> info

清除redis屏幕内容

127.0.0.1:6379> clear

退出redis服务

127.0.0.1:6379> exit

关闭redis服务

127.0.0.1:6379> shutdown

hep指令查看相关指令帮助

127.0.0.1:6379> help type
127.0.0.1:6379> help

三、常用数据类型

1 String类型操作实践

incr/incrby

当存储的字符串是整数时,redis提供了一个实用的命令INCR,其作用是让当前键值递增1,并返回递增后的值;incrby key increment 指定增长系数

127.0.0.1:6379> set num 100
OK
127.0.0.1:6379> incr num
(integer) 101
127.0.0.1:6379> get num
"101"
127.0.0.1:6379> incrby num 500
(integer) 601

说明,如果num不存在,则自动会创建,如果存在自动+1。

decr/decrby

减少指定的整数,DECR key 按照默认步长(默认为1)进行递减,DECRBY key decrement 按照指定步长进行递减

127.0.0.1:6379> decr num
(integer) -1
127.0.0.1:6379> decrby num 10
(integer) -11

append

语法:APPEND key value
向尾部追加值。如果键不存在则创建该键,其值为写的value,即相当于SET key value。返回值是追加后字符串的总长度。

127.0.0.1:6379> set num 1
OK
127.0.0.1:6379> append num 1
(integer) 2

strlen

字符串长度,返回数据的长度,如果键不存在则返回0。注意,如果键值为空串,返回也是0。
语法:STRLEN key

127.0.0.1:6379> strlen a
(integer) 0
127.0.0.1:6379> set a abchd
OK
127.0.0.1:6379> strlen a
(integer) 5

mset/mget

同时设置/获取多个键值
语法:MSET key value [key value …] ; MGET key [key …]

127.0.0.1:6379> mset num1 1 num2 2
OK
127.0.0.1:6379> mget num1 num2
1) "1"
2) "2"

2 Hash类型应用实践

Redis散列类型相当于Java中的HashMap,实现原理跟HashMap一致,一般用于存储对象信息,存储了字段(field)和字段值的映射,一个散列类型可以包含最多232-1个字段。

hset/hget

语法结构

HSET key field value
HGET key field
HMSET key field value [field value…]
HMGET key field [field]
HGETALL key

其中HSET命令当执行插入操作时HSET命令返回1,当执行更新操作时返回0

127.0.0.1:6379> hset user name zhangsan age 10
(integer) 2
127.0.0.1:6379> hset user name wangwu
(integer) 0
127.0.0.1:6379> hget user name
"wangwu"
127.0.0.1:6379> hgetall user
1) "name"
2) "wangwu"
3) "age"
4) "10"

hincrby

127.0.0.1:6379> hincrby article total 1
(integer) 1
127.0.0.1:6379> hincrby article total 2
(integer) 3
127.0.0.1:6379> hget article total
"3"

注意:没有hdecrby自减命令

hmset/hmget

127.0.0.1:6379> hmset user name zhangsan age 10
OK
127.0.0.1:6379> hmget user name age
1) "zhangsan"
2) "10"
127.0.0.1:6379> hgetall user
1) "name"
2) "zhangsan"
3) "age"
4) "10"

hexists

判断属性是否存在

127.0.0.1:6379> hmset user name zhangsan age 10
OK
127.0.0.1:6379> hexists user name
(integer) 1
127.0.0.1:6379> hexists user address
(integer) 0

hdel

删除属性

127.0.0.1:6379> hmset user name zhangsan age 10
OK
127.0.0.1:6379> hdel user name
(integer) 1
127.0.0.1:6379> hgetall user
1) "age"
2) "10"

hkeys/hvals

只获取字段名HKEYS或字段值HVALS

127.0.0.1:6379> hset user name zhangsan age 10
(integer) 2
127.0.0.1:6379> hkeys user
1) "name"
2) "age"
127.0.0.1:6379> hvals user
1) "zhangsan"
2) "10"
127.0.0.1:6379> hlen user
(integer) 2

3 List类型应用实践

Redis的list类型相当于java中的LinkedList,其原理就就是一个双向链表。支持正向、反向查找和遍历等操作,插入删除速度比较快。

lpush

在key对应list的头部添加字符串元素

127.0.0.1:6379> lpush lst1 hello
(integer) 1
127.0.0.1:6379> lpush lst1 world
(integer) 2
127.0.0.1:6379> lrange lst1 0 -1
1) "world"
2) "hello"

其中,Redis Lrange 返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定。 其中 0 表示列表的第一个元素, 1 表示列表的第二个元素,以此类推。 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推

rpush

127.0.0.1:6379> rpush lst1 a
(integer) 1
127.0.0.1:6379> rpush lst1 b
(integer) 2
127.0.0.1:6379> lrange lst1 0 -1
1) "a"
2) "b"

linsert

在key对应list的特定位置之前或之后添加字符串元素

127.0.0.1:6379> rpush lst1 a b
(integer) 2
127.0.0.1:6379> linsert lst1 before b m
(integer) 3
127.0.0.1:6379> lrange lst1 0 -1

lset

设置list中指定下标的元素值(一般用于修改操作)

127.0.0.1:6379> lpush lst1 a
(integer) 1
127.0.0.1:6379> lset lst1 0 aa
OK
127.0.0.1:6379> lset lst1 -1 bb
OK
127.0.0.1:6379> lrange lst1 0 -1
1) "bb"

lrem

从key对应list中删除count个和value相同的元素,count>0时,按从头到尾的顺序删除

ltrim

保留指定key 的值范围内的数据

127.0.0.1:6379> lpush lst1 a b c d e f g
(integer) 7
127.0.0.1:6379> ltrim lst1 1 -1
OK
127.0.0.1:6379> lrange lst1 0 -1
1) "f"
2) "e"
3) "d"
4) "c"
5) "b"
6) "a"

lpop

从list的头部删除元素,并返回删除元素

127.0.0.1:6379> lrange lst1 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
127.0.0.1:6379> lpop lst1
"a"
127.0.0.1:6379> lrange lst1 0 -1
1) "b"
2) "c"
3) "d"
4) "e"

rpop

从list的尾部删除元素,并返回删除元素

127.0.0.1:6379> lrange lst1 0 -1
1) "b"
2) "c"
3) "d"
4) "e"
127.0.0.1:6379> rpop lst1
"e"
127.0.0.1:6379> lrange lst1 0 -1
1) "b"
2) "c"
3) "d"

llen

返回key对应list的长度

127.0.0.1:6379> lrange lst1 0 -1
1) "b"
2) "c"
3) "d"
127.0.0.1:6379> llen lst1
(integer) 3

lindex

返回名称为key的list中index位置的元素

127.0.0.1:6379> lrange lst1 0 -1
1) "b"
2) "c"
3) "d"
127.0.0.1:6379> lindex lst1 1
"c"

rpoplpush

从第一个list的尾部移除元素并添加到第二个list的头部,最后返回被移除的元素值,整个操作是原子的.如果第一个list是空或者不存在返回nil:
rpoplpush lst1 lst1
rpoplpush lst1 lst2

Set类型应用实践

Redis的Set类似Java中的HashSet,是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。Redis中Set集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

sadd

添加元素,重复元素添加失败,返回0

127.0.0.1:6379> sadd set1 zhangsan
(integer) 1
127.0.0.1:6379> sadd set1 lisi
(integer) 1
127.0.0.1:6379> sadd set1 zhangsan
(integer) 0

smembers

获取set元素内容

127.0.0.1:6379> SMEMBERS set1
1) "zhangsan"
2) "lisi"

spop

移除并返回集合中的一个随机元素

scard

获取成员个数

127.0.0.1:6379> scard set1
(integer) 4

smove

移动一个元素到另外一个集合

sunion

并集

四、Jedis应用

说明:Jedis是Java中操作redis的一个客户端,类似通过jdbc访问mysql数据库。在java中远程连接redis,需要将redis.conf配置文件中的bind 127.0.0.1元素注释掉,并且将其保护模式(protected-mode)设置为no(redis3.0之后默认开启了这个策略) ,当修改了配置以后,一定要记得重启redis,然后再进行访问。

pom文件添加依赖

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

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.6</version>
        </dependency>
public class JedisTest {
    Jedis jedis;

    @Before
    public void getRedisConnect() {
        jedis = new Jedis("192.168.58.129", 6379);
        jedis.auth("123456");//假如设置了密码,需要密码认证
        System.out.println(jedis.ping());
    }

    @Test
    public void testSetOper() {
        jedis.sadd("set1", "A", "B", "C", "C");
        System.out.println(jedis.smembers("set1"));
        jedis.close();
    }

    //基于list实现一个先进先出的非阻塞队列队列FIFO
    @Test
    public void testListOper01() {
        jedis.lpush("lst1", "A", "B", "C");
      /* System.out.println(jedis.rpop("lst1"));
        System.out.println(jedis.rpop("lst1"));
        System.out.println(jedis.rpop("lst1"));*/
        System.out.println(jedis.rpop("lst1", jedis.llen("lst1").intValue()));
        System.out.println(jedis.rpop("lst1"));//非阻塞,空了还可以继续取
        jedis.close();
    }

    //list集合的阻塞式队列实现,当从集合取数据时,假如已空,则阻塞,
    @Test
    public void testListOper02() {
        jedis.lpush("lst1", "A", "B", "C");
        jedis.brpop(60, "lst1");//brpop为一个阻塞式方法
        jedis.brpop(60, "lst1");
        jedis.brpop(60, "lst1");
        System.out.println("lst集合已经空啦");
        jedis.brpop(60, "lst1");
        System.out.println("lst集合被阻塞了60秒");
        jedis.close();
    }

    /**
     * hash类型一般用于存储对象(一个对象有很多属性和值)
     */
    @Test
    public void testHashOper01() {
        Map<String, String> map = new HashMap<>();
        map.put("id", "10001");
        map.put("title", "分布式缓存");
        map.put("content", "redis databases");
        jedis.hset("article", map);
        System.out.println(jedis.hgetAll("article"));
    }

    @Test
    public void testHashOper02() {
        jedis.hset("map", "id", "1003");
        jedis.hset("map", "title", "哈哈哈哈");
        System.out.println(jedis.hget("map", "title"));
    }

    @Test
    public void testStrJson() {
        Map<String, Object> map = new HashMap<>();
        map.put("title", "分布式缓存");
        map.put("content", "redis databases");
        //将map对象转换为json格式字符串,这里借助Google公司的gson将对象转换为json字符串
        jedis.set("blog", new Gson().toJson(map));
        System.out.println(jedis.get("blog"));
        //将字符串转换为map进行操作
        System.out.println(new Gson().fromJson(jedis.get("blog"), Map.class));
        jedis.close();
    }

    @Test
    public void testStringOper() throws InterruptedException {
        //与redis建立连接
        Jedis jedis = new Jedis("192.168.58.129", 6379);
        jedis.auth("123456");//假如设置了密码,需要密码认证
        System.out.println(jedis.ping());
        //存储数据(key/value)
        jedis.set("count", "1");
        jedis.set("id", "10001");
        //更新数据
        jedis.expire("id", 10);//设置key的有效时长
        jedis.incr("count");//对key的值进行递增操作
        //获取数据 TimeUnit是java中的枚举类型,SECONDS为枚举类型的实例,sleep底层会调用Thread.sleep()
        TimeUnit.SECONDS.sleep(1);//休眠一秒
        System.out.println("cart.count=" + jedis.get("count"));
        System.out.println("id=" + jedis.get("id"));
        System.out.println("id=" + jedis.strlen("id"));
        //释放资源
        jedis.close();
    }
}

五、JedisPool应用

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

public class JedisPoolTest {
    Jedis jedis;

    @Before
    public void getRedisConnect() {
        jedis = new Jedis("192.168.58.129", 6379);
        jedis.auth("123456");//假如设置了密码,需要密码认证
        System.out.println(jedis.ping());
    }
    @Test
    public void testJedisPool() {
        //定义连接池的配置
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(1000);//最大连接数
        config.setMaxIdle(60);//最大空闲时间(连接不用了要释放)
        //创建连接池
        JedisPool jedisPool = new JedisPool(config, "192.168.58.129", 6379);
        //从池中获取连接
        Jedis resource = jedisPool.getResource();
        //通过jedis连接存储数据
        resource.auth("123456");
        System.out.println(resource.ping());
        resource.set("class", "cgb2104");
        System.out.println(resource.get("class"));
        //将链接返回池中
        resource.close();
        //关闭连接池
        jedisPool.close();
    }
}

六 、RedisTemplate应用

RedisTemplate为SpringBoot工程中操作redis数据库的一个Java对象,此对象封装了对redis的一些基本操作
springboot工程的pom.xml文件加如下依赖

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.3.2.RELEASE</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

application.yml加如下配置

spring:
  redis:
    host: 192.168.64.3
    port: 6379
@SpringBootTest
class ReviewRedisTemplateApplicationTests {
    /**
     * RedisTemplate主要用于操作redis中的复杂对象
     * 底层序列化方式为JDK方式的序列化 JdkSerializationRedisSerializer
     */
    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void testConnection() {
        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        System.out.println(connection.ping());
    }

    @Test
    public void testStringOper() {
        获取用于操作字符串的值对象
        ValueOperations<String, Integer> valueOperations = redisTemplate.opsForValue();
        valueOperations.set("num", 100);
        System.out.println(valueOperations.get("num"));
    }

    @Test//测试list类型数据 数据有序存储(按添加顺序),同时元素允许重复
    void testListOper() {
        ListOperations listOperations = redisTemplate.opsForList();
        listOperations.leftPush("lst1", 100);
        listOperations.leftPushAll("lst1", 200, 300, 400, 500);
        System.out.println(listOperations.range("lst1", 0, -1));
        System.out.println(listOperations.rightPop("lst1"));//FIFO 先进先出
    }

    @Test//测试list类型数据 数据无序,不允许重复
    void setListOper() {
        SetOperations setOperations = redisTemplate.opsForSet();
        setOperations.add("set1", "A", "B", "C", "D");
        System.out.println(setOperations.members("set1"));
        System.out.println(setOperations.remove("set1", "A", "B", "C"));
    }

    @Test//测试hash类型
    void setHashOper() {
        //获取操作hash类型数据的对象
        HashOperations hashOperations = redisTemplate.opsForHash();
        //存数据
        hashOperations.put("blog", "id", 1001);
        hashOperations.put("blog", "title", "redis应用类型");
        //取指定对象对应的字段的值
        System.out.println(hashOperations.get("blog", "id"));
        //取指定对象所有字段的值
        System.out.println(hashOperations.entries("blog"));
    }

    @Test
    void testFlushAll() {
        redisTemplate.execute((RedisConnection redisConnection) -> {
            redisConnection.flushAll();
            return "flush ok";
        });
    }
}

七、RedisTemplate定制

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

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        //1.构建RedisTemplate对象
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        //2.设置连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //3.定义序列化方式(在这里选择jackson)
        Jackson2JsonRedisSerializer redisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        //设置要序列化的域(属性)
        //any表示任意级别访问修饰符修饰的属性 private,public,protected
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        //启动输入域检查(类不能是final修饰的)
        objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(),
                ObjectMapper.DefaultTyping.NON_FINAL,
                JsonTypeInfo.As.PROPERTY);
        redisSerializer.setObjectMapper(objectMapper);
        //4.设置RedisTemplate的序列化
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(redisSerializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(redisSerializer);
        //spring规范中假如修改bean对象的默认特性,建议调用一下afterPropertiesSet()
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

测试

@SpringBootTest
public class CustomRedisTemplate {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void testJsonOper() {
        ValueOperations valueOperations = redisTemplate.opsForValue();
        valueOperations.set("user", new User("zhangsan", 1));//序列化
        System.out.println(valueOperations.get("user"));//反序列化
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class User {
    String name;
    int age;
}

八、redis应用demo

1 单点登录

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

public class SSODemo01 {

    //校验session有效性
    public static boolean isValidSession(String token) {
        //1.建立连接
        Jedis jedis = new Jedis("192.168.64.3", 6379);
        //jedis.auth("123456");
        //2.从redis中获取会话信息
        if (token == null || "".equals(token)) {
            System.out.println("还没有登录");
            jedis.close();
            return false;
        }
        //判断是否登录超时
        String dataStr = jedis.hget("session", "expired" + token);
        if (dataStr == null || "".equals(dataStr)) {
            return false;
        }
        Date expired = new Date(Long.valueOf(dataStr));
        if (expired.before(new Date())) {
            System.out.println("登录超时");
            jedis.close();
            return false;
        }
        return true;
    }

    //执行登录操作
    public static String login(String username, String password) {
        System.out.println("基于username" + username + ",password=" + password + " 进行登录");
        if (!"123456".equals(password)) {
            System.out.println("密码错误");
            return "";
        }
        //1.创建token(一般可以用一个随机的字符串)
        String token = UUID.randomUUID().toString().replace("-", "");
        //2.创建有效登录时长
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MINUTE, 30);
        //3.存储会话信息
        Map<String, String> map = new HashMap<>();
        map.put(token, username);
        map.put("expired" + token, calendar.getTimeInMillis() + "");
        Jedis jedis = new Jedis("192.168.64.3", 6379);
        //jedis.auth("123456");
        jedis.hset("session", map);
        jedis.close();
        return token;
    }

    public static void main(String[] args) {
        System.out.println("===========访问系统资源================");
        //第一次访问redis,检查是否有有效的会话信息
        String token = null;
        boolean flag = isValidSession(token);
        System.out.println(flag ? "第一次:已登录" : "第一次未登录");
        if (!flag) {
            System.out.println("执行登录");
            token = login("zhangsan", "123456");//登录成功的这个token将来响应到客户端
        }
        //第二次访问
        flag = isValidSession(token);
        System.out.println(flag ? "第二次:已登录" : "第二次未登录");
        System.out.println("访问资源");
    }
}

2 投票系统

在很多系统中设计中,都会有一个活动设计,开启一个活动之前,可以对这个活动的支持力度先进行一个调查
在这里插入图片描述

/**
 * 投票系统演示:模拟基于某个活动的投票程序
 * 业务说明:一个用户只能投票一次(不运行重复)
 * 数据结构设计:基于redis的set类型进行数据存储
 */
public class VoteDemo01 {
    /**
     * 说明:多线程环境下不能使用jedis共享变量,我这样写是为了偷懒
     */
    private static Jedis jedis = new Jedis("192.168.64.3", 6379);

    static {
        //jedis.auth("123456");
    }
    /**
     * 进行投票
     * @param activityId 活动id
     * @param userId     用户id
     */
    static void vote(String activityId, String[] userId) {
        jedis.sadd(activityId, userId);
    }

    //查看投票次数
    static Long getVoteCount(String activityId) {
        return jedis.scard(activityId);
    }

    //查看这个活动被哪些人投过票
    static Set<String> getVoteUsers(String activityId) {
        return jedis.smembers(activityId);
    }

    //检查这个用户是否已对这个活动投过票
    static boolean checkVote(String activityId, String userId) {
        return jedis.sismember(activityId, userId);
    }

    //取消投票 TODO
    public static void main(String[] args) {
        String activityId = "10001";
        //1.投票
        vote(activityId, new String[]{"1", "2", "3"});
        //2.获取投票次数
        System.out.println("投票次数" + getVoteCount(activityId));
        //3.输出哪些人投过票
        System.out.println(getVoteUsers(activityId));
        //4.检查用户是否投过票
        boolean flag = checkVote(activityId, "4");
        System.out.println("用户4" + (flag ? "已投过票" : "还没投票"));
    }
}

3 秒杀队列

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

/**
 * 秒杀队列演示:描述逻辑中会将商品抢购信息先写到redis(以队列形式进行存储),因为写redis内存数据库比写mysql数据库快很多倍
 * 算法:先进先出(FIFO)--体现公平性
 */
public class SecondKillDemo01 {

    //商品抢购首先是入队
    static void inQueue(String msg) {//入队
        Jedis jedis = new Jedis("192.168.64.3", 6379);
        //jedis.auth("123456");
        jedis.lpush("queue", msg);
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //底层异步出队(基于这个消息,生成订单,扣减库存....)
    static String outQueue() {//出队
        Jedis jedis = new Jedis("192.168.64.3", 6379);
        jedis.auth("123456");
        return jedis.rpop("queue");
    }

    public static void main(String[] args) {
        //1.多次抢购(模拟在界面上多次点击操作)
        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                inQueue(i + "");
            }
        }).start();
        //2.从队列取内容(模拟后台从队列取数据)
        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {//可加逻辑秒杀时间到,推出循环
                System.out.println(outQueue());
            }
        }).start();
    }
}

4 分布式id

在分布式系统中,数据量将越来越大时,就需要对数据进行分表操作,但是,分表后,每个表中的数据都会按自己的节奏进行自增,很有可能出现ID冲突。这时就需要一个单独的机制来负责生成唯一ID,生成出来的ID也可以叫做 分布式ID

/**
 * 需求:生成一个分布递增id
 * 多张表中基于这个方法生成的id作为主键id值(分布式环境不会采用数据库表中自带的自增策略auto_increment)
 */
public class IdGeneratorDemo01 {
    public static Long getId() {
        Jedis jedis = new Jedis("192.168.64.3", 6379);
        //jedis.auth("123456");
        return jedis.incr("id");
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "--->" + getId());
            }).start();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值