一、SETNX命令的使用
二、SET实现
1)命令说明:
2)set get 可以对已经存在的值重新赋值
3)可以设置过期时间 ex ttl
4)NX 已经存在的值不能再次赋值
5)XX:不存在的key不能赋值,只能修改已经存在的key的value
三、实现分布式锁
1)命令基本实现
2)图解
3)项目中代码实现
4)问题一:那为什么要使用PX/XX 去设置一个超时时间?
5)问题二:设置了超时时间,就确保万无一失了吗?
四、总结

使用redis常用的两种加锁的机制:
SETNX命令
SET命令
一、SETNX命令的使用
SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。

SETNX key value
将 key 的值设为 value ,当且仅当 key 不存在。
若给定的 key 已经存在,则 SETNX 不做任何动作。

127.0.0.1:6379> SETNX test ‘try’
(integer) 1
127.0.0.1:6379> get test
“try”
127.0.0.1:6379> SETNX test ‘tryAgain’
(integer) 0
127.0.0.1:6379> get test
“try”
1
2
3
4
5
6
7
8
第一次给test赋值,返回表示成功;第二次再次尝试给test赋值,返回0,表示失败,并未再次操作,因为值已经存在。
比如有两个线程A和B,两个线程操作相同的key.

虽然流程上是能够走通的.

二、SET实现
如上的NX命令也就是简单介绍一下使用,一般说分布式锁NX命令其实是表达set 的一种命令,如下:

1)命令说明:
SET key value [EX seconds] [PX milliseconds] [NX|XX]
生存时间(TTL,以秒为单位)
Redis 2.6.12 版本开始:(等同SETNX 、 SETEX 和 PSETEX)
EX second :设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。
PX millisecond :设置键的过期时间为 millisecond 毫秒。 SET key value PX millisecond 效果等同于 PSETEX key millisecond value 。
NX :只在键不存在时,才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value 。
XX :只在键已经存在时,才对键进行设置操作。

2)set get 可以对已经存在的值重新赋值
127.0.0.1:6379> set test1 value
OK
127.0.0.1:6379> get test1
“value”
#可以重新对已经存在的值赋值
127.0.0.1:6379> set test1 new-value
OK
127.0.0.1:6379> get test1
“new-value”
1
2
3
4
5
6
7
8
9
3)可以设置过期时间 ex ttl
#设置过期时间为10000秒
127.0.0.1:6379> set test1-expire-time ‘hello’ ex 10000
OK
127.0.0.1:6379> get test1-expire-time
“hello”
#ttl 获取剩余过期时间
127.0.0.1:6379> ttl test1-expire-time
(integer) 9990
127.0.0.1:6379> ttl test1-expire-time
(integer) 9963
127.0.0.1:6379> ttl test1-expire-time
(integer) 9876
1
2
3
4
5
6
7
8
9
10
11
12
4)NX 已经存在的值不能再次赋值
#NX:已经存在的值不能再次赋值
127.0.0.1:6379> set not-test1-key ‘hello’ NX
OK
127.0.0.1:6379> get not-test1-key
“hello”
127.0.0.1:6379> set not-test1-key ‘hello1’ NX
(nil)
127.0.0.1:6379> get not-test1-key
“hello”
1
2
3
4
5
6
7
8
9
5)XX:不存在的key不能赋值,只能修改已经存在的key的value
#XX:未存在的key不能赋值,只能修改已经存在的key的value
127.0.0.1:6379> EXISTS exists-key
(integer) 0
127.0.0.1:6379> set exists-key ‘value’ XX
(nil)
127.0.0.1:6379> set exists-key ‘value’
OK
127.0.0.1:6379> set exists-key ‘value-new’ XX
OK
127.0.0.1:6379> get exists-key
“value-new”
1
2
3
4
5
6
7
8
9
10
11
三、实现分布式锁
1)命令基本实现
命令 SET resource-name anystring NX EX max-lock-time 是一种在 Redis 中实现锁的简单方法

#给lock设置了过期时间为60000毫秒(也可以用ex 6000,单位就变成了秒),当用NX再次赋值,则返回nil,不能重入操作
127.0.0.1:6379> set lock true NX px 60000
OK
127.0.0.1:6379> set lock true NX px 6000
(nil)
127.0.0.1:6379> get lock
“true”
127.0.0.1:6379> ttl lock
(integer) 43
#时间过期后再次get,返回nil,表明key 为 lock的锁已经释放
127.0.0.1:6379> get lock
(nil)
1
2
3
4
5
6
7
8
9
10
11
12
如果setnx 返回ok 说明拿到了锁;如果setnx 返回 nil,说明拿锁失败,被其他线程占用。
换成客户端服务器则是如下:
客户端执行以上的命令:
如果服务器返回 OK ,那么这个客户端获得锁。
如果服务器返回 NIL ,那么客户端获取锁失败,可以在稍后再重试。

2)图解
如上过程通过一个图解一下:

3)项目中代码实现
如下是程序中写的redisConfig。采用了jsdisCluster的set方法。详情:jedis set 的四个重载方法

@Override
public String lock(String key,long expireSecond) {
	final String value = String.valueOf(System.currentTimeMillis());
	//nx : not exists, 只有key 不存在时才把key value set 到redis
	final String nxxx = "NX";
	//ex : seconds 秒
	final String expx = "EX";
	boolean ret;
	if(expireSecond <= 0L)
		//jdeis setnx命令 失效时间
		ret = jedisCluster.setnx(key, value) > 0L;
	else
	    //设置key的过期时间是expireSecond
		ret = "ok".equalsIgnoreCase(jedisCluster.set(key, value, nxxx, expx, expireSecond));
    if(ret){
    	return value;
    }else{
    	return null;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
4)问题一:那为什么要使用PX/XX 去设置一个超时时间?
是怕进程A不讲道理啊,锁没等释放呢,万一崩了,直接原地把锁带走了,导致系统中谁也拿不到锁。

5)问题二:设置了超时时间,就确保万无一失了吗?
如果进程A又不讲道理,操作锁内资源超过笔者设置的超时时间,那么就会导致其他进程拿到锁,等进程A回来了,回手就是把其他进程的锁删了

该如何解决如上场景呢?可以加一层判定,当自己的进程结束或者过期,若value不是自己的值,则不进行删除操作流程。

/**
*
* @param key
* @param keySign 可为空,为空则不断是否为上次获得的锁
* @return
*/
@Override
public boolean unlock(final String key, final String keySign) {
if(StringUtils.isNotBlank(keySign)){
String val = jedisCluster.get(key);
if(!keySign.equals(val)) {
return false;
}
}
if(jedisCluster.del(key) <= 0){
if(jedisCluster.exists(key)){
return false;
}else{
return true;
}
}
return true;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
四、总结
目前项目中是使用了jedis客户端来操作Redis cluster。以上操作都得经过程序员的手动编码,以及能不能保证原子性的问题,当然业务量不大或者并发不大的情况还是很好用的
————————————————
版权声明:本文为CSDN博主「心心念念的小鼠标」的原创文章,遵循CC 4.0 BY原文链接:https://blog.csdn.net/huo065000/article/details/119970629@TOC

欢迎使用Markdown编辑器

你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

新的改变

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

  1. 全新的界面设计 ,将会带来全新的写作体验;
  2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
  3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
  4. 全新的 KaTeX数学公式 语法;
  5. 增加了支持甘特图的mermaid语法1 功能;
  6. 增加了 多屏幕编辑 Markdown文章功能;
  7. 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
  8. 增加了 检查列表 功能。

功能快捷键

撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G

合理的创建标题,有助于目录的生成

直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

如何改变文本的样式

强调文本 强调文本

加粗文本 加粗文本

标记文本

删除文本

引用文本

H2O is是液体。

210 运算结果是 1024.

插入链接与图片

链接: link.

图片: Alt

带尺寸的图片: Alt

居中的图片: Alt

居中并且带尺寸的图片: Alt

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block
var foo = 'bar';

生成一个适合你的列表

  • 项目
    • 项目
      • 项目
  1. 项目1
  2. 项目2
  3. 项目3
  • 计划任务
  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目Value
电脑$1600
手机$12
导管$1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列第二列第三列
第一列文本居中第二列文本居右第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPEASCIIHTML
Single backticks'Isn't this fun?'‘Isn’t this fun?’
Quotes"Isn't this fun?"“Isn’t this fun?”
Dashes-- is en-dash, --- is em-dash– is en-dash, — is em-dash

创建一个自定义列表

Markdown
Text-to- HTML conversion tool
Authors
John
Luke

如何创建一个注脚

一个具有注脚的文本。2

注释也是必不可少的

Markdown将文本转换为 HTML

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n1)!nN 是通过欧拉积分

Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t   . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=0tz1etdt.

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章

2014-01-07 2014-01-09 2014-01-11 2014-01-13 2014-01-15 2014-01-17 2014-01-19 2014-01-21 已完成 进行中 计划一 计划二 现有任务 Adding GANTT diagram functionality to mermaid
  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图:

张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五

这将产生一个流程图。:

链接
长方形
圆角长方形
菱形
  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

Created with Raphaël 2.3.0 开始 我的操作 确认? 结束 yes no
  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. mermaid语法说明 ↩︎

  2. 注脚的解释 ↩︎

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐