redis锁

拓展 ycgwl-cache RedisStorage

/**
     * 如果不存在则 写入缓存并设置过期时间
     * @param key
     * @param value
     * @param expire
     * @return
     */
    public Long setnx(String key, V value,int expire) {
        Jedis j = null;
        String svalue = JsonUtils.toJsonString(value);
        boolean borrowOrOprSuccess = true;

        try {
            j = this.client.getResource();
            Long setnx = j.setnx(key, svalue);
            j.expire(key, expire);

            return setnx;

        } catch (JedisException var10) {
            borrowOrOprSuccess = false;
            if (j != null) {
                this.client.returnBrokenResource(j);
            }

            LOG.error(var10.getMessage(), "EXCEPTION", var10);
        } finally {
            if (borrowOrOprSuccess) {
                this.client.returnResource(j);
            }

        }
        return 0L;
    }

base-dev-service-impl 添加 RedisLock

package lock.lock;

import com.ycgwl.cache.storage.RedisStorage;

import java.util.Random;

public class RedisLock {

    //纳秒和毫秒之间的转换率
    public static final long MILLI_NANO_TIME = 1000 * 1000L;

    //表示被锁定的 value 值
    public static final String LOCKED = "TRUE";

    public static final Random RANDOM = new Random();

    //reids key
    private String key;

    //封装的操作redis的工具
    private RedisStorage storage;

    //是否锁定成功
    private boolean lock = true;

    public RedisLock(String purpose, String key, RedisStorage storage){
        this.key = purpose + "_" + key + "_lock";
        this.storage = storage;
   }

    /**
     * 加锁
     * 使用方式为:
     * lock();
     * try{
     *       executeMethod();
     * }finally{
     *      unlock();
     * }
     * @param timeout timeout的时间范围内轮询锁 纳秒
     * @param expire 设置锁超时时间  秒
     * @return 成功 or 失败
     */
    public boolean lock(long timeout,int expire){

        //获取当前纳秒级时间
        long nanoTime = System.nanoTime();

        //超时时间转纳秒
        timeout *= MILLI_NANO_TIME;
        try {
            //在timeout的时间范围内不断尝试写入锁
            while (System.nanoTime() - nanoTime < timeout) {
                //锁不存在的话,设置锁并设置锁过期时间,即加锁
                if (this.storage.setnx(this.key, LOCKED,expire) == 1) {
                    //设置锁过期时间是为了在没有释放锁的情况下锁过期后消失,不会造成永久阻塞
                    this.lock = true;
                    return this.lock;
                }
                //短暂休眠,避免可能的活锁
                Thread.sleep(3, RANDOM.nextInt(30));
            }
        } catch (Exception e) {
            throw new RuntimeException("获取锁失败",e);
        }
        return false;
    }

    /**
     * 解锁
     */
    public  void unlock() {
        try {
            if(this.lock){
                storage.remove(key);//直接删除
            }
        } catch (Throwable e) {
            throw new RuntimeException("删除锁失败",e);
        }
    }

}

原始方法改私有

新添加加锁接口

    @Resource
    private RedisStorage storage;

    @Override
    public void updateOrderByLock(Long id){
        RedisLock redisLock = new RedisLock("BaseSiteEntity_SiteId", id + "", this.storage);
        boolean result = redisLock.lock(2000, 10);
        //取锁失败
        if(!result){
            throw new RuntimeException("id:"+id+" 获取锁失败");
        }
        try{
            //执行方法
             updateOrderBy(id);
        }finally{
            //释放锁
            redisLock.unlock();
        }

    }

其他  http://www.cnblogs.com/zfzf1/p/7768211.html

时间: 2024-08-30 02:08:39

redis锁的相关文章

redis锁 和悲观锁的并发问题

1.在业务流程前后中,用到了redis锁 和 悲观锁两种不同的锁. 2.汇总账单的时候,从库中读取数据,将读取到的实收额也跟着更新,而在收费的时候添加了悲观锁, 在读账单表的时候 用到了 forupdate,但是redis锁那块同样会产生并发,因为redis锁那块在查询库的时候也需要对账单for update,这样可以防止并发,在悲观锁里若还没更新 则redis锁不去执行更新 3.解决方案 有上面的一个在 redis锁中的查询账单表的时候同样 for update,另外一种则是 对与我们业务相关

(实例篇)php 使用redis锁限制并发访问类示例

1.并发访问限制问题 对于一些需要限制同一个用户并发访问的场景,如果用户并发请求多次,而服务器处理没有加锁限制,用户则可以多次请求成功. 例如换领优惠券,如果用户同一时间并发提交换领码,在没有加锁限制的情况下,用户则可以使用同一个换领码同时兑换到多张优惠券. 伪代码如下: if A(可以换领)         B(执行换领)              C(更新为已换领)             D(结束) 如果用户并发提交换领码,都能通过可以换领(A)的判断,因为必须有一个执行换领(B)后,才会

php 使用redis锁限制并发访问类

1.并发访问限制问题 对于一些需要限制同一个用户并发访问的场景,如果用户并发请求多次,而服务器处理没有加锁限制,用户则可以多次请求成功. 例如换领优惠券,如果用户同一时间并发提交换领码,在没有加锁限制的情况下,用户则可以使用同一个换领码同时兑换到多张优惠券. 伪代码如下: if A(可以换领) B(执行换领) C(更新为已换领) D(结束) 如果用户并发提交换领码,都能通过可以换领(A)的判断,因为必须有一个执行换领(B)后,才会更新为已换领(C).因此如果用户在有一个更新为已换领之前,有多少次

redis锁的进化历程

日常工作中总是会有高并发的场景,需要实现锁机制来保证序列性,接下来我们一步一步实现一个 单机Redis下完全可靠的Redis锁(ps: 如果是Redis集群的话,就存在主从切换锁失效的问题,解决这个问题的话就比较麻烦了,这里不做讨论,现有的解决方案有redlock,大家可以看下它的实现原理) Redis锁 第一版(php实现): //加锁 public function lock($key) { $redisConnect = Redis::connection(); $v = $redisCo

利用Redis锁解决高并发问题

这里我们主要利用Redis的setnx的命令来处理高并发. setnx 有两个参数.第一个参数表示键.第二个参数表示值.如果当前键不存在,那么会插入当前键,将第二个参数做为值.返回 1.如果当前键存在,那么会返回0. 创建库存表 CREATE TABLE `storage` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `number` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=Inno

php实习redis锁机制

<?php class Redis_lock { public static function getRedis() { $redis = new redis(); $redis->connect('182.254.208.72', 3838, 0); $redis->auth('eh.123'); return $redis; } public static function lock($key, $expire = 60) { if(!$key) { return false; }

分布式定时任务的redis锁实现

一个web项目如果部署为分布式时,平时常见的定时服务在一定的间隔时间内,可能出现多次重复调用的问题.而此时由于是不同容器之间的竞争,因此需要容器级别的锁 Redis为单进程单线程模式,采用队列模式将并发访问变为串行访问.Redis本身没有锁的概念,Redis对于多个客户端连接并不存在竞争.但是可以通过setnx来实现锁 SETNX命令(SET if Not exists) 语法: SETNX key value 功能:将 key 的值设为 value ,当且仅当 key 不存在:若给定的 key

Redis锁构造

单线程与隔离性 Redis是使用单线程的方式来执行事务的,事务以串行的方式运行,也就是说Redis中单个命令的执行和事务的执行都是线程安全的,不会相互影响,具有隔离性. 在多线程编程中,对于共享资源的访问要十分的小心: import threading num = 1 lock = threading.Lock() def change_num(): global num for i in xrange(100000): #lock.acquire() num += 5 num -= 5 #lo

redis 锁

import threading import time from redis import Redis class Myredis(Redis): def __init__(self): super(Myredis, self).__init__(host="192.168.31.21", port=6379, db=0, password="a123456") def mysetex(self,name,time,value): print("this