Maven redis redisTemplate

说明:jedispool、redisTemplate

jedispool、redisTemplate这是俩种利用redis缓存的分布式锁。

redisTemplate

Pom.xml

 

<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.3.4.RELEASE</version>
</dependency>

 

applicationContext-config.xml

 

<bean id="configurationProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:properties/redis.properties</value>
</list>
</property>
</bean>

Spring.xml

<bean id="redisDistributedLock" class="com.hp.wandafilm.pts.util.RedisDistributedLock">
<property name="redisTemplate" ref="redisTemplate"></property>
</bean>
 
<!-- redisTemplate配置,redisTemplate是对Jedis的对redis操作的扩展,有更多的操作,封装使操作更便捷   -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" p:connection-factory-ref="jedisConnectionFactory"/>            
 
 <!-- Jedis ConnectionFactory 数据库连接配置-->  
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">  
<property name="poolConfig" ref="jedisPoolConfig" />
<property name="hostName" value="${redis.host}" />
<property name="port" value="${redis.port}" />
</bean>  
 
<!-- Jedis 连接池配置--> 
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">  
        <property name="maxIdle" value="${redis.maxIdle}" />  
        <property name="maxTotal" value="${redis.maxTotal}" />  
        <property name="maxWaitMillis" value="${redis.maxWaitMillis}" />  
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />  
</bean>

 

Redis.properties

redis.host=服务ip
redis.port=6379
redis.maxIdle=11
redis.maxTotal=12
redis.maxWaitMillis=1000
redis.testOnBorrow=true

RedisDistributedLock .java

 

import java.util.HashMap;
import java.util.Map;
 
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.RedisTemplate;
 
import redis.clients.jedis.Jedis;
 
/**
 * redis分布式锁
 * @author robin
 *
 */
public class RedisDistributedLock {
    private static final Log log = LogFactory.getLog(RedisDistributedLock.class);
 
    private RedisTemplate<String, Long> redisTemplate;
    
/**
 * 锁失效时长,默认1天
 */
private long lockTimeOut = 1000 * 3600 * 24L;
/**
 * 获取锁等待时长(获取单个锁的时候使用),默认20s
 */
private long lockWaitTime = 1000 * 20L;
/**
 * 获取锁自旋时长(获取一组锁的时候使用),默认1s
 */
private long spinTime = 1000 * 1L;
/**
 * 休眠时长,以毫秒为单位
 * 默认为1000毫秒
 */
private long sleeptime = 1000 * 1L;
/**
 * 当前时间
 */
private long currentLockTime;
/**
 * 加锁
 * @return 返回 true 成功 false 失败
 */
public boolean lock(String key){
log.info(String.format("获取分布式锁请求参数【锁的名称 = %s,锁失效时长 = %s,获取锁等待时间 = %s,获取锁自旋时长 = %s,休眠时间 = %s】", key, lockTimeOut, lockWaitTime, spinTime, sleeptime));
try{
//设置超时时间
 RedisCacheManager redisManage = new RedisCacheManager(redisTemplate);
 Map<String, Long> expires = new HashMap<String, Long>();
 expires.put(key, lockTimeOut);
//如果key不存在, 直接返回false
if(!StringUtils.isNotBlank(key)){
log.info(String.format("获取分布式锁失败,分布式锁%s不存在!", "key"));
throw new Exception("抛出异常信息");//修改为自定义异常
}
//等待时间小于失效时间否则不合理
if (lockWaitTime > lockTimeOut) {
log.info(String.format("设置分布式锁过期时间[%s]或获取分布式锁等待时间[%s]有误]!",String.valueOf(lockTimeOut),String.valueOf(lockWaitTime)));
throw new Exception("抛出异常信息");//修改为自定义异常
}
//获取当前时间
currentLockTime = System.currentTimeMillis();
//等待超时时间
long lockWaitTimeAt = lockWaitTime + currentLockTime;
while(true) {
//取得当前时间
currentLockTime = System.currentTimeMillis();
//等待超时时间 1468919062570 1468919068071
if(lockWaitTimeAt <= currentLockTime){
break;
}
//获取锁
Boolean boo = redisTemplate.opsForValue().setIfAbsent(key,currentLockTime);
if(boo){
//获取所成功
                log.info(String.format("直接获取锁key:%s,当前时间:%s", key,currentLockTime));
                //设置锁失效时间
                redisManage.setExpires(expires);
                return true;  
}else{
 //其他线程占用了锁  
                log.info(String.format("检测到锁被占用{key: %s, 当前时间: %s}", key, currentLockTime));  
                Long otherLockTime = redisTemplate.opsForValue().get(key);  
                if(otherLockTime == null) {  
                    // 其他系统释放了锁  
                    // 立刻重新尝试加锁
                 log.info(String.format("检测到锁被释放{key: %s, 当前时间: %s}", key, currentLockTime));  
                    continue;  
                } else {  
                    if(currentLockTime - otherLockTime >= lockTimeOut) {  
                        //锁超时  
                        //尝试更新锁  
                     log.info(String.format("检测到锁超时{key: {%s}, 当前时间: {%s}, 检测到锁的时间: {%s}, 超时时间:{%s}}", key, currentLockTime,otherLockTime,lockTimeOut));
                        Long otherLockTime2 = redisTemplate.opsForValue().getAndSet(key, currentLockTime);  
                        if(otherLockTime2 == null || otherLockTime.equals(otherLockTime2)) {  
                            log.info(String.format("获取到超时锁{key: {%s}, currentLockTime: {%s}, otherLockTime: {%s}, otherLockTime2: {%s}}", key, currentLockTime, otherLockTime, otherLockTime2));  
                            //设置锁失效时间
                         redisManage.setExpires(expires);
                            return true;  
                        } else {  
                            sleep();  
                            //重新尝试加锁  
                            log.info(String.format("重新尝试加锁{key: %s, 当前时间: %s}", key, currentLockTime));
                            continue;  
                        }  
                    } else {  
                        //锁未超时  
                        sleep();  
                        //重新尝试加锁  
                        log.info(String.format("重新尝试加锁{key: %s, 当前时间: %s}", key, currentLockTime));  
                        continue;  
                    }  
                }  
}
}
}catch (Exception e) {
log.error(String.format("获取分布式锁异常,异常信息:" + e.getMessage(),e));
//抛出自定义异常信息
}
return false;
}
/**
 * 解锁
 * @param key
 * @return
 */
public boolean unLock(String key) {  
log.info(String.format("解锁{key: {%s}}", key));  
redisTemplate.delete(key);  
        return true;  
    }  
/**
 * 休眠<br />
 * @param sleeptime
 */
private void sleep() {
try {
Thread.sleep(sleeptime);
} catch (InterruptedException e) {
log.error("线程异常中断异常,"+e.getMessage(),e);
//抛出自定义异常信息
}
}
 
public long getLockTimeOut() {
return lockTimeOut;
}
 
/**
 * 锁失效时长,默认1天 单位:S
 * @param lockTimeOut
 */
public void setLockTimeOut(long lockTimeOut) {
this.lockTimeOut = lockTimeOut * 1000;
}
 
public long getLockWaitTime() {
return lockWaitTime;
}
 
/**
 * 获取锁等待时长(获取单个锁的时候使用),默认20s 单位:S
 * @param lockWaitTime
 */
public void setLockWaitTime(long lockWaitTime) {
this.lockWaitTime = lockWaitTime  * 1000;
}
 
public long getSpinTime() {
return spinTime;
}
 
/**
 * 获取锁自旋时长(获取一组锁的时候使用),默认1s 单位:S
 * @param spinTime
 */
public void setSpinTime(long spinTime) {
this.spinTime = spinTime  * 1000;
}
 
public long getSleeptime() {
return sleeptime;
}
 
/**
 * 休眠时长,默认1s 单位 :S
 * @param sleeptime
 */
public void setSleeptime(long sleeptime) {
this.sleeptime = sleeptime  * 1000;
}
 
public long getCurrentLockTime() {
return currentLockTime;
}
 
public void setCurrentLockTime(long currentLockTime) {
this.currentLockTime = currentLockTime  * 1000;
}
public RedisTemplate<String, Long> getRedisTemplate() {
return redisTemplate;
}
 
public void setRedisTemplate(RedisTemplate<String, Long> redisTemplate) {
this.redisTemplate = redisTemplate;
}
 
@Test
    public void test(){
      Jedis jedis = new Jedis("10.199.88.169", 6379);
         try {
             long l = jedis.setnx("qwe","qwe");
            // RedisTemplate<String, Long> redisTemplate = redisTemplate.opsForValue().setIfAbsent();
             
             long ll = jedis.setnx("qwe","qwe");
             
             System.out.println(l);
             System.out.println(ll);
             
         }catch (Exception e) {
          e.printStackTrace();
 }
    }
}

redistDemo.java

public class redistDemo {
public static void main(String[] args) {
 ApplicationContext appContext5 = new ClassPathXmlApplicationContext(new String[]{"classpath*:spring/applicationContext-config.xml","classpath*:spring/spring.xml"});
  RedisDistributedLockrd = (RedisDistributedLock)appContext5.getBean("redisDistributedLock");
 rd.setLockTimeOut(20L);
 rd.setLockWaitTime(30L);
 boolean bo = rd.lock("redistDemo");
 System.out.println(bo);
}
}

JedisPool

Pom.xml

<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.4.2</version>
</dependency>

applicationContext-config.xml

 

<bean id="configurationProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:properties/redis.properties</value>
</list>
</property>
</bean>

Spring.xml

<!-- redis-jedisPool分布式锁加载 -->
<bean id="redisBillLockHandler" class="com.hp.wandafilm.pts.util.RedisBillLockHandler">
<property name="jedisPool" ref="jedisPool"></property>
</bean>
 
 <!-- jedisPool -->
    <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
    <constructor-arg index="0" ref="jedisPoolConfig"/>
    <constructor-arg index="1" value="${redis.host}"/>
    <constructor-arg index="2" value="${redis.port}" type="int"/>
</bean>
 
<!-- Jedis 连接池配置--> 
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">  
        <property name="maxIdle" value="${redis.maxIdle}" />  
        <property name="maxTotal" value="${redis.maxTotal}" />  
        <property name="maxWaitMillis" value="${redis.maxWaitMillis}" />  
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />  
</bean>

 

Redis.properties

redis.host=服务ip
redis.port=6379
redis.maxIdle=11
redis.maxTotal=12
redis.maxWaitMillis=1000
redis.testOnBorrow=true

 

IBillIdentify.java

public class IBillIdentify {
private StringpayOrderId;
private StringKey = "iIBillIdentify_KEY_" ;
public Object uniqueIdentify(){
return Key+payOrderId;
}
 
public String getPayOrderId() {
return payOrderId;
}
 
public void setPayOrderId(String payOrderId) {
this.payOrderId = payOrderId;
}
}

RedisBillLockHandler.java

 

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
 
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.CollectionUtils;
 
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.exceptions.JedisConnectionException;
 
/**
 * 
 * @author long
 *
 */
public class RedisBillLockHandler  {
 
    private static final LogLOGGER = LogFactory.getLog(RedisBillLockHandler.class);
 
    private static final int DEFAULT_SINGLE_EXPIRE_TIME = 3;
    
    private static final int DEFAULT_BATCH_EXPIRE_TIME = 6;
 
    private JedisPool jedisPool;
    
    /**
     * 获取锁  如果锁可用   立即返回true,  否则返回false
     * @author 
     * @see com.fx.platform.components.lock.IBillLockHandler#tryLock(com.fx.platform.components.lock.IBillIdentify)
     * @param billIdentify
     * @return
     */
    public boolean tryLock(IBillIdentify billIdentify) {
        return tryLock(billIdentify, 0L,null);
    }
 
    /**
     * 锁在给定的等待时间内空闲,则获取锁成功 返回true, 否则返回false
     * @author 
     * @see com.fx.platform.components.lock.IBillLockHandler#tryLock(com.fx.platform.components.lock.IBillIdentify,
     *      long, java.util.concurrent.TimeUnit)
     * @param billIdentify
     * @param timeout
     * @param unit
     * @return
     */
    public boolean tryLock(IBillIdentify billIdentify,long timeout, TimeUnit unit) {
        String key = (String) billIdentify.uniqueIdentify();
        Jedis jedis = null;
        try {
            jedis = getResource();
            long nano = System.nanoTime();
            do {
                LOGGER.debug("try lock key: " + key);
                Long i = jedis.setnx(key, key);
                if (i == 1) {
                    jedis.expire(key, DEFAULT_SINGLE_EXPIRE_TIME);
                    LOGGER.debug("get lock, key: " + key +" , expire in " +DEFAULT_SINGLE_EXPIRE_TIME +" seconds.");
                    return Boolean.TRUE;
                } else {// 存在锁
                    if (LOGGER.isDebugEnabled()) {
                        String desc = jedis.get(key);
                        LOGGER.debug("key: " + key +" locked by another business:" + desc);
                    }
                }
                if (timeout == 0) {
                    break;
                }
                Thread.sleep(300);
            } while ((System.nanoTime() - nano) < unit.toNanos(timeout));
            return Boolean.FALSE;
        } catch (JedisConnectionException je) {
            LOGGER.error(je.getMessage(), je);
            returnBrokenResource(jedis);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        } finally {
            returnResource(jedis);
        }
        return Boolean.FALSE;
    }
 
    /**
     * 如果锁空闲立即返回   获取失败 一直等待
     * @author 
     * @see com.fx.platform.components.lock.IBillLockHandler#lock(com.fx.platform.components.lock.IBillIdentify)
     * @param billIdentify
     */
    public void lock(IBillIdentify billIdentify) {
        String key = (String) billIdentify.uniqueIdentify();
        Jedis jedis = null;
        try {
            jedis = getResource();
            do {
                LOGGER.debug("lock key: " + key);
                Long i = jedis.setnx(key, key);
                if (i == 1) {
                    jedis.expire(key, DEFAULT_SINGLE_EXPIRE_TIME);
                    LOGGER.debug("get lock, key: " + key +" , expire in " +DEFAULT_SINGLE_EXPIRE_TIME +" seconds.");
                    return;
                } else {
                    if (LOGGER.isDebugEnabled()) {
                        String desc = jedis.get(key);
                        LOGGER.debug("key: " + key +" locked by another business:" + desc);
                    }
                }
                Thread.sleep(300);
            } while (true);
        } catch (JedisConnectionException je) {
            LOGGER.error(je.getMessage(), je);
            returnBrokenResource(jedis);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        } finally {
            returnResource(jedis);
        }
    }
 
    /**
     * 释放锁
     * @author 
     * @see com.fx.platform.components.lock.IBillLockHandler#unLock(com.fx.platform.components.lock.IBillIdentify)
     * @param billIdentify
     */
    public void unLock(IBillIdentify billIdentify) {
        List<IBillIdentify> list = new ArrayList<IBillIdentify>();
        list.add(billIdentify);
        unLock(list);
    }
 
    /**
     * 批量获取锁  如果全部获取   立即返回true, 部分获取失败 返回false
     * @author 
     * @date 2013-7-22 下午10:27:44
     * @see com.fx.platform.components.lock.IBatchBillLockHandler#tryLock(java.util.List)
     * @param billIdentifyList
     * @return
     */
    public boolean tryLock(List<IBillIdentify> billIdentifyList) {
        return tryLock(billIdentifyList, 0L,null);
    }
    
    /**
     * 锁在给定的等待时间内空闲,则获取锁成功 返回true, 否则返回false
     * @author 
     * @param billIdentifyList
     * @param timeout
     * @param unit
     * @return
     */
    public boolean tryLock(List<IBillIdentify> billIdentifyList,long timeout, TimeUnit unit) {
        Jedis jedis = null;
        try {
            List<String> needLocking = new CopyOnWriteArrayList<String>();    
            List<String> locked = new CopyOnWriteArrayList<String>();    
            jedis = getResource();
            long nano = System.nanoTime();
            do {
                // 构建pipeline,批量提交
                Pipeline pipeline = jedis.pipelined();
                for (IBillIdentify identify : billIdentifyList) {
                    String key = (String) identify.uniqueIdentify();
                    needLocking.add(key);
                    pipeline.setnx(key, key);
                }
                LOGGER.debug("try lock keys: " + needLocking);
                // 提交redis执行计数
                List<Object> results = pipeline.syncAndReturnAll();
                for (int i = 0; i < results.size(); ++i) {
                    Long result = (Long) results.get(i);
                    String key = needLocking.get(i);
                    if (result == 1) {    //setnx成功,获得锁
                        jedis.expire(key, DEFAULT_BATCH_EXPIRE_TIME);
                        locked.add(key);
                    } 
                }
                needLocking.removeAll(locked);    // 已锁定资源去除
                
                if (CollectionUtils.isEmpty(needLocking)) {
                    return true;
                } else {    
                    // 部分资源未能锁住
                    LOGGER.debug("keys: " + needLocking +" locked by another business:");
                }
                
                if (timeout == 0) {    
                    break;
                }
                Thread.sleep(500);    
            } while ((System.nanoTime() - nano) < unit.toNanos(timeout));
 
            // 得不到锁,释放锁定的部分对象,并返回失败
            if (!CollectionUtils.isEmpty(locked)) {
                jedis.del(locked.toArray(new String[0]));
            }
            return false;
        } catch (JedisConnectionException je) {
            LOGGER.error(je.getMessage(), je);
            returnBrokenResource(jedis);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        } finally {
            returnResource(jedis);
        }
        return true;
    }
 
    /**
     * 批量释放锁
     * @author 
     * @see com.fx.platform.components.lock.IBatchBillLockHandler#unLock(java.util.List)
     * @param billIdentifyList
     */
    public void unLock(List<IBillIdentify> billIdentifyList) {
        List<String> keys = new CopyOnWriteArrayList<String>();
        for (IBillIdentify identify : billIdentifyList) {
            String key = (String) identify.uniqueIdentify();
            keys.add(key);
        }
        Jedis jedis = null;
        try {
            jedis = getResource();
            jedis.del(keys.toArray(new String[0]));
            LOGGER.debug("release lock, keys :" + keys);
        } catch (JedisConnectionException je) {
            LOGGER.error(je.getMessage(), je);
            returnBrokenResource(jedis);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        } finally {
            returnResource(jedis);
        }
    }
    
    /**
     * @author 
     * @date 2013-7-22 下午9:33:45
     * @return
     */
    private Jedis getResource() {
        return jedisPool.getResource();
    }
    
    
    public JedisPool getJedisPool() {
return jedisPool;
}
 
public void setJedisPool(JedisPool jedisPool) {
this.jedisPool = jedisPool;
}
 
/**
     * 销毁连接
     * @author 
     * @param jedis
     */
    private void returnBrokenResource(Jedis jedis) {
        if (jedis ==null) {
            return;
        }
        try {
            //容错
            jedisPool.returnBrokenResource(jedis);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
    }
    
    /**
     * @author 
     * @param jedis
     */
    private void returnResource(Jedis jedis) {
        if (jedis ==null) {
            return;
        }
        try {
            jedisPool.returnResource(jedis);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
    }
    
}

 

redistDemo.java

public class redistDemo {
public static void main(String[] args) {
 ApplicationContext appContext5 =new ClassPathXmlApplicationContext(new String[]{"classpath*:spring/applicationContext-config.xml","classpath*:spring/spring.xml"});
 RedisBillLockHandler rb = (RedisBillLockHandler)appContext5.getBean("redisBillLockHandler");
 IBillIdentify billIdentify = new IBillIdentify();
 billIdentify.setPayOrderId("1231232312312345");
 boolean bo = rb.tryLock(billIdentify);
 System.out.println(bo);
}
}