美文网首页
redis 的安装和简单使用

redis 的安装和简单使用

作者: slicn | 来源:发表于2018-01-07 14:50 被阅读0次
    • 一种nosql 单线程的数据库做缓存的简单使用
    • 对curd的操作,为了保证数据的一致性,除了查询,其它操作都要进行数据更新和删除
    • redis的协议:Redis服务器与客户端通过RESP(REdis Serialization Protocol)协议通信,了解了Redis协议的基本数据类型,就可以通过Socket与Redis Server进行通信,客户端和服务器发送的命令或数据一律以 \r\n (CRLF)结尾。
    • 缓存击穿 指查询一个一定不存在的数据要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞;解决方法如果一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短
    • 缓存雪崩 缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩;解决方案在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,降低几率;或则加锁,队列
    • 关于缓存击穿和雪崩参考

    安装服务

    • http://www.redis.cn/ 下载最新redis4.01
    • #tar -zxvf redis... --解压
    • #mv file filepath --移动到你想安装的目录
    • #cd /redis
    • #make MALLOC=libc --管理内存碎片
    • #make && make install --编译并安装
    • #cd src && redies-server 如图 image.png

    配置

    • #vi /home/redis/src/redis.conf --编写配置文件,写入已下配置,指定端口-父进程pid-守护进程 image.png
    • #通过src/redis-server redis.conf 启动 通过#redis-cli shutdown 来停止服务
    • 会有两个端口打开未发现有什么错误,可以禁用ip6, image.png
    • #firewall-cmd --zone=public --add-port=6379/tcp --perment
    • #vi /usr/lib/systemd/system/redis.service --编写服务单元交与systemd 管理 image.png

    rdb和aof 两种持久化方案详情1详情2

    • rdb 是基于快照的,通过save seconds frequency,进行周期性的备份默认开启,当服务器出现故障可能会丢失最后一次的数据。数据恢复速度快适合数据的备份。 image.png
    • aof 是基于日志记录的,保持了高一致性。数据比较全面文件比较大恢复稍慢。默认是关闭的通过appendonly yes开启。


      image.png

    简单的使用

    1. 使用java操作jedis客户端
    • 编写jedisManager
    导入依赖
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.9.0</version>
      </dependency>
    
    redis的连接初始化类
    
    public class JedisManager {
        private static String host = "192.168.1.200";
        private static int port = 6379;
        private JedisPoolConfig jpc;
        private static JedisPool jedisPool;
        private static int timeOut;
    
        /**
         * 初始化连接池
        **/
        static {
            if (timeOut == 0){
                timeOut = Protocol.DEFAULT_TIMEOUT;
            }
            jedisPool = new JedisPool(host,port);
        }
    
        /**
         * 从连接池中获取连接
        **/
        public static Jedis getJedis(){
            if (jedisPool != null){
                return jedisPool.getResource();
            }else throw new NullPointerException("jedisPool is null");
        }
    
        /**
         * 把连接返回给jedispool
        **/
        public static void  returnResource(Jedis jedis) {
            if (jedis != null){
                jedisPool.close();
            }
        }
    
        /**
         * 关闭连接池
        **/
        public void shutDown(){
            if (jedisPool != null){
                jedisPool.destroy();
            }
        }
    }
    
    String类型的测试
    
    public class JedisDao {
        //存储字符串
        public void cacheString(){
            Jedis jedis = JedisManager.getJedis();
            System.out.println(jedis);
            jedis.set("name","hahaha");
            System.out.println(jedis.get("name"));
            //拼接
            jedis.append("name","is 爸爸");
            System.out.println(jedis.get("name"));
            JedisManager.returnResource(jedis);
        }
    
    }
    
    测试结果
    
    redis.clients.jedis.Jedis@7bb11784
    hahaha
    hahahais 爸爸
    Process finished with exit code 0
    
    1. 整合spring 分别在service层缓存,利用spirng aop 对目标方法进行缓存
    导入依赖
    
    <dependency>
          <groupId>redis.clients</groupId>
          <artifactId>jedis</artifactId>
           <version>2.9.0</version>
      </dependency>
      <dependency>
          <groupId>org.springframework.data</groupId>
           <artifactId>spring-data-redis</artifactId>
            <version>1.7.2.RELEASE</version>
     </dependency>
    <dependency>
        <groupId>aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
         <version>1.5.4</version>
      </dependency>
    
    redis.properties
    
    redis.host=192.168.1.200
    redis.port=6379
    redis.password=
    #最大空闲数
    redis.maxIdel=300
    #连接池连接数
    redis.maxActive=600
    #最大等待时间
    redis.maxWait=1000
    #实例均用
    redis.testOnBorrow=true
    
    reids-cfg.xml
    
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
        <!--引入redis参数文件-->
         <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
            <property name="order" value="1"/>
            <property name="ignoreUnresolvablePlaceholders" value="true"/>
            <property name="locations">
                <list>
                    <value>classpath:redis.properties</value>
                </list>
            </property>
        </bean>
        <!--连接池-->
        <bean id="jedisConfig" class="redis.clients.jedis.JedisPoolConfig">
            <property name="maxTotal" value="${redis.maxActive}"/>
            <property name="maxIdle" value="${redis.maxIdel}"/>
            <property name="maxWaitMillis" value="${redis.maxWait}"/>
            <property name="testOnBorrow" value="${redis.testOnBorrow}"/>
    
        </bean>
    
        <!--连接工厂-->
        <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
            <property name="hostName" value="${redis.host}"/>
            <property name="port" value="${redis.port}"/>
            <property name="password" value="${redis.password}"/>
            <property name="poolConfig" ref="jedisConfig"/>
           <property name="usePool" value="true"/>
    
        </bean>
    
        <!-- redis操作模板-->
        <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
            <property name="connectionFactory" ref="connectionFactory"/>
            <!--     如果不配置Serializer,那么存储的时候只能使用String,如果用对象类型存储,那么会提示错误 can't cast to String!!!-->
            <property name="keySerializer">
                <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
            </property>
            <property name="valueSerializer">
                <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
            </property>
            <!--开启事务-->
            <property name="enableTransactionSupport" value="true"/>
        </bean>
    
    </beans>
    
    放入spring的主配置文件
    
        <!--redis-->
        <import resource="redis-cfg.xml"/>
    
    • 测试在service层进行缓存
     需要的工具类
    
    @Component
    public class RedisCacheUtil {
    
        @Autowired
        private RedisTemplate<Serializable,Object> redisTemplate;
    
        /**
         * 删除对应的value
        **/
        public void remove(final String... args){
            for (String key:args){
               remove(key);
            }
        }
        public boolean remove(String key){
            boolean flag = false;
            try {
                if (exists(key)){
                    redisTemplate.delete(key);
                    flag = true;
                }
            }catch (Exception e) {
                System.out.println(e.toString());
            }
            return flag;
        }
    
        public boolean exists(String key) {
            return redisTemplate.hasKey(key);
        }
    
    
        /**
         * 删除keys
        **/
        public void removePattern(final String pattern){
            Set<Serializable> keys = redisTemplate.keys(pattern);
            if (keys.size()>0){
                redisTemplate.delete(keys);
            }
        }
    
        /**
         * 根据key读取缓存
        **/
        public Object get(final String key){
             return redisTemplate.opsForValue().get(key);
        }
        
        /**
         * 写入缓存
        **/
        public boolean set(final String key, Object value){
            try {
                redisTemplate.opsForValue().set(key,value);
                return true;
            }catch (Exception e){
                System.out.println(e.toString());
                return false;
            }
        }
    
        public boolean set(final String key, Object value, Long time){ //设置过期时间
            try {
                redisTemplate.opsForValue().set(key, value);
                redisTemplate.expire(key,time, TimeUnit.SECONDS);
                return true;
            }catch (Exception e){
                return false;
            }
        }
    }
    
    
    缓存的容器
    
    /**
     * Created by: jun on 2018/1/7.
     * description: 创建redis的储存器接口
     */
    public interface RedisCacheStorage<k,v> {
        //key,value 普通类型
        boolean set(k key, v value);    //永久缓存
        boolean set(k key, v value, Long time); //time内缓存
        boolean remove(k key);  //删除
        v get(k key);   //获取
     }
    
    // 实现的接口
    @Component
    public class RedisCacheStorageImpl<v> implements RedisCacheStorage<String,v> {
    
        @Autowired
        private RedisCacheUtil redisCacheUtil;
    
        @Override
        public boolean set(String key, v value) {
            return redisCacheUtil.set(key,value);
        }
    
        @Override
        public boolean set(String key, v value, Long time) {
            return redisCacheUtil.set(key,value,time);
        }
    
        @Override
        public boolean remove(String key) {
            return redisCacheUtil.remove(key);
        }
    
        @Override
        public v get(String key) {
            return (v) redisCacheUtil.get(key);
        }
    }
    
    实体类,一定要序列化,spirng 才能进行装配
    
    public class User implements Serializable {
    
        private Integer id;
        private String name;
        private String pwd;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getPwd() {
            return pwd;
        }
    
        public void setPwd(String pwd) {
            this.pwd = pwd;
        }
    }
    
    开始缓存
    
    @Service
    public class UserServiceImpl implements UserService {
    
        private static final String cacheKey = "userEntity"; //缓存的key
        private static final Long time = 10000l;
    
        @Autowired
        private UserMapper userMapper;
        @Autowired
        private RedisCacheStorage cacheStorage;
    
        @Override
        public List<User> select() {
            //先查找缓存
            List<User> userList;
            userList = (List<User>) cacheStorage.get(cacheKey);
            if (userList != null) {
                System.out.println("读取了缓存");
                return userList;
            } else {
                //开始查找数据库,放入缓存
                userList = userMapper.selectAll();
                cacheStorage.set(cacheKey, userList);
                System.out.println("已添加缓存");
                return userList;
            }
        }
    
    

    测试结果


    image.png
    • 测试基于aop配置文件目标方法的缓存
    实现MethodInterceptor接口的切面,在redis.properties中写入需要缓存的方法如果与aop拦截的方法对应则进行缓存
    
    /**
     * Created by: jun on 2018/1/3.
     * description: 实现spring MethodInterceptor接口,使用aop对方法级的进行缓存。
     *              根据配置文件给不同的方法加入判断是否缓存数据,第一次从缓存中读取,并将结果进行缓存
     */
    public class MethodCacheInterceptor implements MethodInterceptor {
    
        @Autowired
        private RedisCacheUtil redisCacheUtil;
        private List<String> cacheClassList;    //缓存的serice类
        private List<String> cacheMethodList;    //缓存的方法
        private Long timeOut = 1000l;   //过期时间
        private String resourcesName = "redis.properties";  //缓存的配置文件
        private String fileClassValue = "cacheClass";    //配置文件设置缓存的类字段
        private String fileMethodValue = "cacheMethod";     //配置文件中缓存的方法字段
    
    
        /**
         * 初始化读取需要缓存的类和方法
         * 在reids.properties中添加缓存的方法和类
         *
        **/
        public MethodCacheInterceptor() throws IOException {
            // 在 resources 下读取配置文件
            InputStream in = ConfProLoader.getClassPathFile(resourcesName);
            Properties p = new Properties();
            p.load(in);
            //分割,获取每个类和方法
            String[] cacheClass = p.getProperty(fileClassValue).split(",");
            String[] cacheMethod = p.getProperty(fileMethodValue).split(",");
            //将方法和类存入list
            cacheClassList = new ArrayList<String>(cacheClass.length);
            cacheMethodList = new ArrayList<String>(cacheMethod.length);
            int maxLength = cacheClass.length > cacheMethod.length ? cacheClass.length
                    : cacheMethod.length;
            for (int i=0; i<maxLength; i++){
                if (i<cacheClass.length) cacheClassList.add(cacheClass[i]);
                if (i<cacheMethod.length) cacheMethodList.add(cacheMethod[i]);
                }
            }
    
    
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            //得到方法和参数列表
            String targetName = invocation.getThis().getClass().getName();
            String methodName = invocation.getMethod().getName();
            Object[] argument = invocation.getArguments();
            String key = getCacheKey(targetName,methodName,argument);
            System.out.println("key: "+key);
            //是否缓存方法 /否则放行
            System.out.println("拦截的类"+targetName);
            if (isAddCache(targetName,methodName)){
                //若果缓存存在,直接读取否则进行缓存
                if (redisCacheUtil.exists(key)){
                    System.out.println("开始读取缓存");
                    return redisCacheUtil.get(key);
                }
                Object value = invocation.proceed();   //对方法的结果进行缓存
                if (value != null){
                    System.out.println("开始缓存");
                    redisCacheUtil.set(key,value,timeOut);
                }
            }
            return invocation.proceed();
        }
    
        /**
         * 检查是否需要添加缓存
        **/
        public boolean isAddCache(String targetName,String metnodName){
            boolean flag= false;
            if (cacheClassList.contains(targetName) || cacheMethodList.contains(metnodName)) flag = true;
            return flag;
        }
    
    
        /**
         * 创建缓存的key
        **/
        public String getCacheKey(String targetName, String methodName, Object[] arguments){
            StringBuffer sb = new StringBuffer();
            sb.append(targetName).append("_").append(methodName);
            for (int i=0; i<arguments.length; i++){
                if (arguments.length>0) sb.append("_").append(arguments[i]);
            }
            return sb.toString();
        }
    }
    
    在reids的资源文件中写入需要缓存的类和方法。如果拦截的方法和配置文件中对应,则对该方法进行缓存
    
    host=192.168.1.200
    port=6379
    password=
    
    #连接池连接数
    maxTotal=400
    #最大空闲数
    maxIdel=300
    #最大等待时间
    maxWait=1000
    #实例均用
    testOnBorrow=true
    
    
    #需要缓存的类
    cacheClass=comm.tianzhuan.web.service.impl.UserServiceImpl,test1
    #要缓存的方法
    cacheMethod=selectt,hahaha
    
    #设置缓存失效时间
    test=60
    test1=60
    defaultCacheExpireTime=3600
    
    
    spirng中配置aop
    
     <!--配置拦截器实现方法的缓存-->
        <bean id="methodCacheInterceptor" class="com.tianzhuan.common.cache.MethodCacheInterceptor"/>
        <aop:config proxy-target-class="true">
            <!-- 切入点 -->
            <aop:pointcut id="redisCache" expression="execution(* com.tianzhuan.web.service.impl.*.*(..))"/>
            <!--拦截器-->
            <aop:advisor advice-ref="methodCacheInterceptor" pointcut-ref="redisCache"/>
        </aop:config>
    

    测试的结果

    @Test
        public void test(){
            List<User> userList = userService.select();
            System.out.println(userList);
        }
    
    image.png

    相关文章

      网友评论

          本文标题:redis 的安装和简单使用

          本文链接:https://www.haomeiwen.com/subject/axwmgxtx.html