Redis实现分布式锁
时间:2015-10-18 13:04 来源:linux.it.net.cn 作者:IT
在服务器端,如果不对用户连击行为做出控制,很容易到出现数据异常,尤其涉及到软妹子的问题时;解决问题的方法有:数据库加锁,代码加锁等.本文将从代码加锁方式实现,适应于单机或者分布式集群等
-
普通方式
-
直接看代码
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package com.whereta.jedis;
import org.springframework.stereotype.Component; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool;
import javax.annotation.Resource; import java.util.Calendar; import java.util.Date; import java.util.concurrent.TimeUnit;
/**
* Created by vincent on 15-10-14.
*/ @Component("jedisLock") public class JedisLock {
public class CacheName {
public static final String ADD_BEAN_AFTER_CHECK_LOCK_KEY = "ADDBeanAfterCheckLock";
}
@Resource
private JedisPool jedisPool;
public void addBeanAfterCheck(int userId) {
Jedis jedis = jedisPool.getResource();
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.MILLISECOND, 0);
Date calendarTime = calendar.getTime();
long time = calendarTime.getTime();
//以用户id为key,不同用户调用同一个方法不会加锁 String key = CacheName.ADD_BEAN_AFTER_CHECK_LOCK_KEY + ":" + userId;
try {
if (jedis != null) {
Long lock = jedis.setnx(key, time + "");
while (lock == 0) {
TimeUnit.MILLISECONDS.sleep(50);
lock = jedis.setnx(key, time + "");
}
//设置超时时间 jedis.expire(key, 3);
}
//自己的业务逻辑处理
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (jedis != null) {
jedis.del(key);
jedis.close();
}
}
}
}
-
示例中以用户id为key加锁:不同用户访问该方法的时候不会排斥等待
-
锁机制的实现利用了Redis的setnx方法:如果数据库里key存在了则不存储数据,返回0
-
redis的该方法是线程安全的,可以放心使用
-
aop方式
-
示例代码
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package com.whereta.jedis;
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool;
import javax.annotation.Resource; import java.util.Calendar; import java.util.Date; import java.util.concurrent.TimeUnit;
/**
* Created by vincent on 15-10-14.
*/ @Aspect @Component public class JedisLockAop {
@Resource
private JedisPool jedisPool;
@Around("execution(public * com.heli.core.pay.soaservice.impl.*.*(..))")
public Object serviceAOP(ProceedingJoinPoint point) {
Object proceed = null;
Jedis jedis = jedisPool.getResource();
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.MILLISECOND, 0);
Date calendarTime = calendar.getTime();
long time = calendarTime.getTime();
//请求参数数组 Object[] args = point.getArgs();
//key可以自定义 String key = JedisLock.CacheName.ADD_BEAN_AFTER_CHECK_LOCK_KEY + ":" + args[0];
try {
if (jedis != null) {
Long lock = jedis.setnx(key, time + "");
while (lock == 0) {
TimeUnit.MILLISECONDS.sleep(50);
lock = jedis.setnx(key, time + "");
}
//设置超时时间 jedis.expire(key, 3);
}
//用户业务处理 proceed = point.proceed();
return proceed;
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
} finally {
if (jedis != null) {
jedis.del(key);
jedis.close();
}
}
}
}
-
使用Spring Aop的环绕方法
-
具体key值可以自定义涉及,譬如:ip,时间等
(责任编辑:IT)
在服务器端,如果不对用户连击行为做出控制,很容易到出现数据异常,尤其涉及到软妹子的问题时;解决问题的方法有:数据库加锁,代码加锁等.本文将从代码加锁方式实现,适应于单机或者分布式集群等
(责任编辑:IT) |