☀️Terry

- - 草木逢春,雨过天晴🌈。

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

 多数据源 数据源1为锁控制,数据源2自定义,可用于存储。

  锁:当出现并发的时候为了保证数据的一致性,不会出现并发问题,假设,用户1修改一条信息,用户2也同时修改,会按照顺序覆盖自修改的值,为了避免这种情况的发生,使用redis锁,实现控制。只可以一个用户去修改那条数据,当出现多个用户,会报错,抛出异常提示。

依赖:

<dependencies>
        <!--######################### 定义 redis 版本 #########################-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--######################### 定义 jedis 版本 #########################-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
        <!--######################### 定义 json 版本 #########################-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
        </dependency>
        <!--######################### 定义 lang3 版本 #########################-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
    </dependencies>

redis配置类

package cn.lsr.redis.core;

/**
 * @Description: redis参数配置类
 * @Package: lsr-microservice
 * @author: Hacker_lsr@126.com
 * @version: V1.0
 **/
public class RedisPropertiesConfig {
    /**
     * redis 数据库
     */
    private Integer database;

    /**
     * redis 主机地址
     */
    private String host;

    /**
     * 端口
     */
    private Integer port;

    /**
     * 密码
     */
    private String password;

    /**
     * 驱动类名
     */
    private Integer timeout;


    private Pool pool;

    //get set

    public static class Pool {

        private Integer maxActive;

        private Integer minIdle;

        private Integer maxIdle;

        private Integer maxWait;

        //get set
    }
}

redis工厂基类:

package cn.lsr.redis.core;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

import java.time.Duration;

/**
 * @Description: redis配置基类
 * @Package: lsr-microservice
 * @author: Hacker_lsr@126.com
 * @version: V1.0
 **/
public class LSRBaseRedisConfig {
    /**
     * jedis 连接工厂
     * @param redisPropertiesConfig
     * @return
     */
    public JedisConnectionFactory buildJedisConnectionFactory(RedisPropertiesConfig redisPropertiesConfig) {
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
        jedisConnectionFactory.setDatabase(redisPropertiesConfig.getDatabase());
        jedisConnectionFactory.setHostName(redisPropertiesConfig.getHost());
        jedisConnectionFactory.setPort(redisPropertiesConfig.getPort());
        jedisConnectionFactory.setPassword(redisPropertiesConfig.getPassword());
        jedisConnectionFactory.setTimeout(redisPropertiesConfig.getTimeout());

        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxIdle(redisPropertiesConfig.getPool().getMaxIdle());
        poolConfig.setMinIdle(redisPropertiesConfig.getPool().getMinIdle());
        poolConfig.setMaxTotal(redisPropertiesConfig.getPool().getMaxActive());
        poolConfig.setMaxWaitMillis(redisPropertiesConfig.getPool().getMaxWait());
        poolConfig.setTestOnBorrow(true);

        jedisConnectionFactory.setPoolConfig(poolConfig);
        return jedisConnectionFactory;

    }
    private Duration timeToLive = Duration.ZERO;
    public void setTimeToLive(Duration timeToLive) {
        this.timeToLive = timeToLive;
    }

    /**
     * 缓存
     * @param factory
     * @return
     */
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // 配置序列化(解决乱码的问题)
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(timeToLive)
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }
//
//        RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate);
//        return redisCacheManager;
    //}

    /**
     * RedisTemplate 初始化 序列化和反序列化
     * @param redisConnectionFactory
     * @return
     */
    public RedisTemplate buidRedisTemplate(RedisConnectionFactory redisConnectionFactory) {

        /* Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
        template.setConnectionFactory(redisConnectionFactory);
        //template.setKeySerializer(jackson2JsonRedisSerializer);
        //使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashKeySerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
        */
        RedisSerializer stringSerializer = new StringRedisSerializer();
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(stringSerializer);
        return redisTemplate;
    }
}

数据库操作工厂:

package cn.lsr.redis.core;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

/**
 * @Description: 数据操作redis配置
 * @Package: lsr-microservice
 * @author: Hacker_lsr@126.com
 * @version: V1.0
 **/
@Configuration
public class LSRDBRedisConfig extends LSRBaseRedisConfig {
    private static final Logger log = LoggerFactory.getLogger(LSRDBRedisConfig.class);
    /**
     *  初始化 jedis lsrDBRedisProperties 连接工厂 -- lsrDBJedisConnectionFactory
     * @param redisPropertiesConfig
     * @return
     */
    @Bean(name = "lsrDBJedisConnectionFactory")
    @Override
    public JedisConnectionFactory buildJedisConnectionFactory(@Qualifier("lsrDBRedisProperties")RedisPropertiesConfig redisPropertiesConfig) {
        log.info("lsrDBRedisConfig RedisPropertiesConfig:{}",redisPropertiesConfig);
        return super.buildJedisConnectionFactory(redisPropertiesConfig);
    }

    /**
     * 初始化工厂中 lsrDBJedisConnectionFactory  的 lsrDBRedisTemplate
     * @param redisConnectionFactory
     * @return
     */
    @Bean(name = "lsrDBRedisTemplate")
    @Override
    public RedisTemplate <Object, Object> buidRedisTemplate(@Qualifier("lsrDBJedisConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
        return super.buidRedisTemplate(redisConnectionFactory);
    }

//    @Bean
//    @Override
//    public CacheManager cacheManager(@Qualifier("lbsRedisTemplate")RedisTemplate redisTemplate) {
//        return super.cacheManager(redisTemplate);
//    }

    /**
     * 启动加载配置文件 yml  redis 连接参数
     * @return
     */
    @Bean(name = "lsrDBRedisProperties")
    @ConfigurationProperties(prefix = "spring.redis.db")
    public RedisPropertiesConfig getBaseDBProperties() {
        return new RedisPropertiesConfig();
    }

}

锁实现工厂:

package cn.lsr.redis.core;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

/**
 * @Description: 锁的配置
 * @Package: lsr-microservice
 * @author: Hacker_lsr@126.com
 * @version: V1.0
 **/
@Configuration
public class LSRLockRedisConfig extends LSRBaseRedisConfig {
    private static final Logger log = LoggerFactory.getLogger(LSRLockRedisConfig.class);

    /**
     *  初始化 jedis  lsrLockRedisConfig 连接工厂 --  lsrLockJedisConnectionFactory
     * @param redisPropertiesConfig
     * @return
     */
    @Primary
    @Bean(name = "lsrLockJedisConnectionFactory")
    @Override
    public JedisConnectionFactory buildJedisConnectionFactory(@Qualifier("lsrLockRedisConfig")RedisPropertiesConfig redisPropertiesConfig) {
        log.info("MasterRedisConfig RedisPropertiesConfig:{}",redisPropertiesConfig);
        return super.buildJedisConnectionFactory(redisPropertiesConfig);
    }

    /**
     * 初始化工厂中 lsrLockJedisConnectionFactory  的 lsrLockRedisTemplate
     * @param redisConnectionFactory
     * @return
     */
    @Bean(name = "lsrLockRedisTemplate")
    @Override
    public RedisTemplate<Object, Object> buidRedisTemplate(@Qualifier("lsrLockJedisConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
        return super.buidRedisTemplate(redisConnectionFactory);
    }

//    @Bean
//    @Override
//    public CacheManager cacheManager(@Qualifier("lbsRedisTemplate")RedisTemplate redisTemplate) {
//        return super.cacheManager(redisTemplate);
//    }

    /**
     * 启动加载配置文件 yml  redis 连接参数
     * @return
     */
    @Bean(name = "lsrLockRedisConfig")
    @ConfigurationProperties(prefix = "spring.redis.lock")
    public RedisPropertiesConfig getBaseDBProperties() {
        return new RedisPropertiesConfig();
    }

}

定义redis 锁实现逻辑

package cn.lsr.redis.core;

import cn.lsr.redis.utils.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @Description: 用redis实现分布式锁
 * @Package: lsr-microservice
 * @author: Hacker_lsr@126.com
 * @version: V1.0
 **/
@Component
public class RedisLock {
    /**
     * 不写默认使用带有@Primary的lsrLockRedisTemplate
     */
    @Resource(name = "lsrLockRedisTemplate")
    private RedisTemplate redisTemplate;
    @Resource(name = "lsrDBRedisTemplate")
    private RedisTemplate redisTemplate2;

    /**
     * 加锁
     * @param key id
     * @param value 时间戳
     * @return
     */
    public  boolean lock(String key, String value) {
        //setIfAbsent相当于jedis中的setnx,如果能赋值就返回true,如果已经有值了,就返回false
        //即:在判断这个key是不是第一次进入这个方法
        if (redisTemplate.opsForValue().setIfAbsent(key, value)) {
            //第一次,即:这个key还没有被赋值的时候
            return true;

        }
        String current_value = (String) redisTemplate.opsForValue().get(key);
        if (!StringUtils.object2String(current_value).equals("")
                //超时了
                && Long.parseLong(current_value) < System.currentTimeMillis()) {////并发 重置value 让其获得锁失败!
            redisTemplate.opsForValue().getAndSet(key, value);//String newValue = (String) redisTemplate.opsForValue().get(key);
            if (!StringUtils.object2String(newValue).equals("")
                    //如果两个线程同时调用这个方法,当同时走到①的时候,
                    // 无论怎么样都有一个线程会先执行②这一行,
                    //假设线程1先执行②这行代码,那redis中key对应的value就变成了value
                    //然后线程2再执行②这行代码的时候,获取到的old_value就是value,
                    //那么value显然和他上面获取的current_value是不一样的,则线程2是没法获取锁的
                    && newValue.equals(current_value)) {
                return true;
            }
        }
        return false;
    }


    /**
     * 释放锁
     * @param key id
     * @param value 时间戳
     */
    public void unlock(String key, String value) {
        try {
            if (StringUtils.object2String(redisTemplate.opsForValue().get(key)).equals(value)) {
                redisTemplate.opsForValue().getOperations().delete(key);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

封装redis锁实现为借口:

package cn.lsr.redis.lock;


import cn.lsr.redis.utils.RedisResult;

/**
 * @Description: redis接口
 * @Package: lsr-microservice
 * @author: Hacker_lsr@126.com
 * @version: V1.0
 **/
public interface RedisInterFace {
    /**
     * 获取锁服务
     * @param id 唯一标识
     * @param value 时间戳
     * @return
     */
    public RedisResult lock(String id, String value);

    /**
     *  解锁服务
     * @param id 唯一标识
     * @param value 时间戳
     */
    public RedisResult unlock(String id, String value);
}

redis锁借口实现:

package cn.lsr.redis.lock.imp;

import cn.lsr.redis.core.RedisLock;
import cn.lsr.redis.lock.RedisInterFace;
import cn.lsr.redis.utils.RedisResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Description: redis锁实现
 * @Package: lsr-microservice
 * @author: Hacker_lsr@126.com
 * @version: V1.0
 **/
@Service
public class RedisInterFaceImp implements RedisInterFace {
    private static final Logger log = LoggerFactory.getLogger(RedisInterFaceImp.class);
    @Autowired
    private RedisLock redisLock;
    @Override
    public RedisResult lock(String id, String value) {
        if (!redisLock.lock(id,value)){
            log.info("获取redis失败 错误!!标识为:"+id);
            return RedisResult.error(false,"获得redis锁错误!!!! 标识为:"+id);
            //throw new RuntimeException("活得锁失败!");
        }
        log.info("获得redis锁成功 标识为:"+id);
        return RedisResult.success(true,"获得redis锁成功 标识为:"+id);
    }

    @Override
    public RedisResult unlock(String id, String value) {
        log.info("释放redis锁成功 标识为:"+id);
        redisLock.unlock(id,value);
        return RedisResult.success(true,"释放redis锁成功 标识为:"+id);
    }
}

调用使用模拟

package cn.lsr.user.controller.user;


/**
 * = =  用户控制器
 *
 * @Version: 1.0
 * @Author: Hacker_lsr@126.com
 */
@Api(tags = "用户信息控制器")
@Controller
public class UserController {
    private TestServerPollThread testServerPollThread;
    /**
     * 注入redis服务
     */
    @Resource
    private RedisInterFace redisInterFace;

    }
    /**
     * 功能描述: <br>
     * 〈〉根据主键删除
     * @Param: [uid]
     * @Return: com.lsr.common.utils.Result
     * @Author: Hacker_lsr@126.com
     */
    @RequiresPermissions("delete")
    @RequestMapping("/delete/user")
    @ResponseBody
    public Result deleteUser(String uid){
        String time = System.currentTimeMillis()+"";
        RedisResult lock = redisInterFace.lock(uid, time);
        if (lock.getStatus()==200){
            //userMapper.deleteByPrimaryKey(uid);
            userMapper.selecTest("admin");
        }else {
            throw new RuntimeException(lock.getMessages());
        }
        RedisResult unlock = redisInterFace.unlock(uid, time);
        log.info("reids锁释放:{}",unlock.getMessages());
        return Result.success("操作成功");
    }
    public static void main(String[] args) {
        Jedis jedis = new Jedis("192.168.0.104",6379);
        jedis.ping();
        System.out.println(jedis.ping());
    }
}

 

posted on 2020-02-28 09:31  ☀️Terry  阅读(444)  评论(0编辑  收藏  举报