1、前言 在Java中,我们通过锁来避免由于竞争而造成的数据不一致问题。通常我们使用synchronized 、Lock来实现。但是Java中的锁只能保证在同一个JVM进程内中可用
在Java中,我们通过锁来避免由于竞争而造成的数据不一致问题。通常我们使用synchronized 、Lock来实现。但是Java中的锁只能保证在同一个JVM进程内中可用,在跨JVM进程,例如分布式系统上则不可靠了。
分布式锁,是一种思想,它的实现方式有很多,如基于数据库实现、基于缓存(Redis等)实现、基于ZooKeeper实现等等。为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件
以下代码实现了基于redis中间件的分布式锁。加锁的过程中为了保障setnx(设置KEY)和expire(设置超时时间)尽可能在一个事务中,使用到了lua脚本的方式,将需要完成的指令一并提交到redis中;
package com.demo.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JSONRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// key采用String的序列化方式
template.seTKEySerializer(new StringRedisSerializer());
// value序列化方式采用jackson
template.setValueSerializer(new GenericJackson2jsonRedisSerializer());
template.afterPropertiesSet();
return template;
}
}
package com.demo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.WEB.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
@RestController
@RequestMapping("/redis")
public class RedisLockController {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@RequestMapping(value = "/lock/{key}/{uid}/{expire}")
public Long lock(@PathVariable("key") String key, @PathVariable("uid") String uid, @PathVariable("expire") Integer expire) {
Long result = null;
try {
//调用lua脚本并执行
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
redisScript.setResultType(Long.class);//返回类型是Long
//lua文件存放在resources目录下的redis文件夹内
redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis/redis_lock.lua")));
result = redisTemplate.execute(redisScript, Arrays.asList(key), uid, expire);
System.out.println("lock==" + result);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
@RequestMapping(value = "/unlock/{key}/{uid}")
public Long unlock(@PathVariable("key") String key, @PathVariable("uid") String uid) {
Long result = null;
try {
//调用lua脚本并执行
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
redisScript.setResultType(Long.class);//返回类型是Long
//lua文件存放在resources目录下的redis文件夹内
redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis/redis_unlock.lua")));
result = redisTemplate.execute(redisScript, Arrays.asList(key), uid);
System.out.println("unlock==" + result);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then
return redis.call('expire',KEYS[1],ARGV[2])
else
return 0
end
if redis.call("exists",KEYS[1]) == 0 then
return 1
end
if redis.call('get',KEYS[1]) == ARGV[1] then
return redis.call('del',KEYS[1])
else
return 0
end
key123为key,thread12345为value标识锁的主人,300为该锁的超时时间
加锁:锁主人为thread12345
Http://127.0.0.1:8080/redis/lock/key123/thread12345/300
解锁:解锁人为thread123456
http://127.0.0.1:8080/redis/unlock/key123/thread123456
解锁:解锁人为thread12345
http://127.0.0.1:8080/redis/unlock/key123/thread12345
thread12345加的锁,thread123456是解不了的,只有等thread12345自己解锁或者锁的超时时间过期
thread12345加的锁,thread12345自己随时可以解锁,也可以等锁的超时时间过期
到此这篇关于基于Redis实现分布式锁的方法(lua脚本版)的文章就介绍到这了,更多相关Redis实现分布式锁内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
--结束END--
本文标题: 基于Redis实现分布式锁的方法(lua脚本版)
本文链接: https://lsjlt.com/news/125713.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0