一、简介
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();
}
}
}