redis中使用java脚本实现分布式锁
转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/115.html?1455860390
edis被大量用在分布式的环境中,自然而然分布式环境下的锁如何解决,立马成为一个问题。例如我们当前的手游项目,服务器端是按业务模块划分服务器的,有应用服,战斗服等,但是这两个vm都有可能同时改变玩家的属性,这如果在同一个vm下面,就很容易加锁,但如果在分布式环境下就没那么容易了,当然利用redis现有的功能也有解决办法,比如redis的脚本。
redis在2.6以后的版本中增加了Lua脚本的功能,可以通过eval命令,直接在RedisServer环境中执行Lua脚本,并且可以在Lua脚本中调用Redis命令。
使用脚本的好处:
1.减少网络开销:可以把一些要批量处理的功能,发在一个脚本里面执行,减少客户端和redis的交互次数
2.原子操作:这主要就是我们在这边主要利用的功能,在分布式环境下保证数据的原子性。
3.复用:客户端发送的脚本会永久的存储在redis中,这就意味着其他客户端可以复用这一脚本而不需要使用代码完成同样的逻辑。
下面先看一段lua脚本:
代码如下:
local food=redis.call('hget',KEYS[1],'food');
food=food+ARGV[1];
redis.call('hset',KEYS[1],'food',food);
local diamond=redis.call('hget',KEYS[1],'diamond');
diamond=diamond+ARGV[2];
redis.call('hset',KEYS[1],'diamond',diamond);
注:redis.call是我们在脚本中调用redis命令,KEYS和ARGV2个数组,分别是键和参数,下标都是从1开始的,不是0。
这段脚本的功能是取出 KEYS指定的玩家food(粮草)和diamond(玉石),然后就行修改,最后保存在redis中,脚本的执行,保证了整个操作的原子性。
下面我们用java代码来看看具体的实现过程
代码如下:
Jedis jedis = new Jedis("192.168.128.128", 6379);
// 1.初始玩家数据到redis中
GamePlayer player = new GamePlayer();
player.setId(1001);
player.setName("ksfzhaohui");
player.setFood(100);
player.setDiamond(100);
Map<String, String> beanMap = BeanUtil.warp(player);// 将对象转换成map
String beanKey = getRedisBeanKey(player.getClass(), player.getId());
System.out.println("key:" + beanKey);
jedis.hmset(beanKey, beanMap);// 将玩家数据保存到redis中
首先模拟了一个玩家将玩家信息保存在redis中,这边的Id随便写了一个,正常的情况下都是通过redis的命令incr生成一个id
结果: 
代码如下:
String script = "local food=redis.call('hget',KEYS[1],'food');"
+ "food=food+ARGV[1];"
+ "redis.call('hset',KEYS[1],'food',food);"
+ "local diamond=redis.call('hget',KEYS[1],'diamond');"
+ "diamond=diamond+ARGV[2];"
+ "redis.call('hset',KEYS[1],'diamond',diamond);";
List<String> keys = new ArrayList<String>();
keys.add(beanKey);
List<String> args = new ArrayList<String>();
args.add("100");
args.add("100");
// 3.执行脚本
jedis.eval(script, keys, args);
指定键和参考,执行脚本,结果:

BeanUtil代码:
代码如下:
public class BeanUtil {
private static Logger logger = Logger.getLogger(BeanUtil.class);
private static final String CLASS = "class";
/**
* 将指定的对象数据封装成map
*
* @param bean
* 对象数据
* @return
*/
@SuppressWarnings("all")
public static Map<String, String> warp(Object bean) {
Map<String, String> propertyMap = new HashMap<String, String>();
try {
PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass())
.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : ps) {
String propertyName = propertyDescriptor.getName();
if (propertyName != null && !propertyName.equals(CLASS)) {
Method getter = propertyDescriptor.getReadMethod();
if (getter != null) {
propertyMap.put(propertyName,
String.valueOf(getter.invoke(bean, null)));
}
}
}
} catch (Exception e) {
logger.error(e);
}
return propertyMap;
}
}
redis中使用java脚本实现分布式锁的更多相关文章
- redis集群+JedisCluster+lua脚本实现分布式锁(转)
https://blog.csdn.net/qq_20597727/article/details/85235602 在这片文章中,使用Jedis clien进行lua脚本的相关操作,同时也使用一部分 ...
- 【spring boot】【redis】spring boot基于redis的LUA脚本 实现分布式锁
spring boot基于redis的LUA脚本 实现分布式锁[都是基于redis单点下] 一.spring boot 1.5.X 基于redis 的 lua脚本实现分布式锁 1.pom.xml &l ...
- 在redis中使用lua脚本
在实际工作过程中,可以使用lua脚本来解决一些需要保证原子性的问题,而且lua脚本可以缓存在redis服务器上,势必会增加性能. 不过lua也会有很多限制,在使用的时候要注意. 在Redis中执行Lu ...
- 新姿势!Redis中调用Lua脚本以实现原子性操作
背景:有一服务提供者Leader,有多个消息订阅者Workers.Leader是一个排队程序,维护了一个用户队列,当某个资源空闲下来并被分配至队列中的用户时,Leader会向订阅者推送消息(消息带有唯 ...
- 【JSP】JSP中的Java脚本
前言 现代Web开发中,在JSP中嵌入Java脚本不是推荐的做法,因为这样 不利于代码的维护.有很多好的,替代的方法避免在JSP中写Java脚本.本文仅做为JSP体系技术的一个了解. 类成员定 ...
- redis中使用lua脚本
lua脚本 Lua是一个高效的轻量级脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能 使用脚本的好处 1.减少网络开销,在Lua脚 ...
- Redis中的原子操作(2)-redis中使用Lua脚本保证命令原子性
Redis 如何应对并发访问 使用 Lua 脚本 Redis 中如何使用 Lua 脚本 EVAL EVALSHA SCRIPT 命令 SCRIPT LOAD SCRIPT EXISTS SCRIPT ...
- Redis学习笔记(三)使用Lua脚本实现分布式锁
Redis在2.6推出了脚本功能,允许开发者使用Lua语言编写脚本传到Redis中执行. 使用Lua脚本的好处如下: 1.减少网络开销:本来5次网络请求的操作,可以用一个请求完成,原先5次请求的逻辑放 ...
- Redis中的Java分布式缓存
为什么在分布式Java应用程序中使用缓存?今天学习了两节优锐课讲解分布式缓存的内容,收获颇多,分享给大家. 在提高应用程序的速度和性能时,每毫秒都是至关重要的.例如,根据Google的一项研究,如果网 ...
随机推荐
- DBNull 与 求和方法
public int CountMoney() { if (!DBNull.Value.Equals(Eval("LawyerMoney")) && !DBNull ...
- node学习笔记(二)
process.stdout(); //标准输出流 process.stdout.write() //提供了比console.log更底层的接口 process.stdin(); //标准输入流 // ...
- JS制作计算器(键盘版)
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 31.0px Consolas; color: #2b7ec3 } p.p2 { margin: 0.0px ...
- JavaScript-BOM-history:保存当前窗口打开后成功访问过的url历史记录栈
history:保存当前窗口打开后成功访问过的url历史记录栈history.go(n):前进n步前进一步:history.go(1);后退一步:history.go(-1);刷新:history.g ...
- jquery 监听input输入值事件
<html> <head> <title></title> <script type="text/javascript" sr ...
- centos/redhat安装mysql
1.从http://dev.mysql.com/downloads/repo/ 下载对应的rpm文件,我的是版本7,所以下载:mysql-community-release-el7-5.noarch. ...
- Bootstrap库之Modals
Bootstrap库之Modals. Bootstrap是Twitter推出的一个开发工具包,包含了一些比较常用的CSS,JavaScript代码.使用Bootstrap可以加快前端开发的速度.本站( ...
- rdc21n(研发与设计综合讨论)博客开通了!
rdc21n是“Research and Design Comprehensive discussioN”,其中21表示Comprehensive discussioN中间的21个字母(不包含空格), ...
- 对于git的认识
对于git的认识,我只想说,我不会把他的概念复制下来在博客上再发一遍,我对于他的了解是代源码的开放编写.对于git我会在今后去认真的理解他,不是所谓的抄袭.不会的东西我会尽力去学习.
- Linux环境变量配置
/etc/profile:此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行.并从/etc/profile.d目录的配置文件中搜集shell的设置./etc/bashrc:为每一个运 ...