JavaWeb--------Java实现Redis缓存

 

一. Redis 简介

Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。

Redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。 

Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。

二. Redis Java缓存使用

1) 下载安装redis:从redis的官网下载安装包,并解压至目标文件中。注意稳定版本和非稳定版本的区别。

JavaWeb--------Java实现Redis缓存_第1张图片

2) 启动redis服务:若想要正常连接到redis服务器,则必须先启动redis服务。windows系统中,找到安装包下的redis-server.exe,双击,出现以下界面,则说明已正常启动。

JavaWeb--------Java实现Redis缓存_第2张图片

3) 使用jedis操作:Java程序可以通过jedis来操作redis数据。简单实现了查询所有key,往缓存中添加key,value,查看缓存数据等。注意,必须先启动redis服务器,否则会报错。

JavaWeb--------Java实现Redis缓存_第3张图片

4) 使用redis-client客户端操作:windows系统,找到安装包下的redis-client.exe,运行,通过命令行方式操作数据。比如:查看所有的key,删除某个值,添加值等。

JavaWeb--------Java实现Redis缓存_第4张图片

5) redis命令:redis有String,Hash,List,Set,SortedSet 5种数据类型,Key,pub/sub,transaction,script ,server,connection等,每个操作有对应的命令。熟悉各种命令,是使用redis的基础。

JavaWeb--------Java实现Redis缓存_第5张图片

6) Codis:codis是豌豆荚开源的分布式server,是一个分布式 Redis 解决方式。

三. 在Java中对Redis 缓存的操作

Redis 是一个NoSQL数据库,也是一个高性能的key-value数据库。一般我们在做Java项目的时候,通常会了加快查询效率,减少和数据库的连接次数,我们都会在代码中加入缓存功能。Redis的高效缓存功能给我们解决了难题。下面我主要讲讲在Java项目中怎么去连接Redis服务器以及需要注意的事项。
1)导入必须的Jar包
使用Java操作Redis需要两个必须的Jar包:jedis-2.5.1.jar 和  commons-pool2-2.0.jar 。每个版本可以不一样,根据你自己下载的为准。
2)实现RedisUtils工具类
把连接Redis服务器的代码封装到一个工具类里面,这样就可以直接调用攻击类来获取Redis的服务。
RedisUtils工具类代码如下:  以下代码和网上其他的实现类大同小异,其实这个没什么创新的东西。

下面代码需要注意的地方:config.setMaxTotal(MAX_TOTAL); 由于我的jedis版本是2.5的,所有没有setMaxActive这个方法。

public class RedisUtils {
    //Redis服务器IP
    private static String ADDR = "192.168.125.130";
    
    //Redis的端口号
    private static int PORT = 6379;
    
    //访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接
    private static String AUTH = "123456";
    
    //可用连接实例的最大数目,默认值为8;
    private static int MAX_TOTAL = 512;
    
    //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
    private static int MAX_IDLE = 50;
    
    //等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。
    private static int MAX_WAIT = 10000;
    
    private static int TIMEOUT = 10000;
    
    //在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
    private static boolean TEST_ON_BORROW = true;
    
    private static JedisPool jedisPool = null;
    
    /**
     * 初始化Redis连接池
     */
    static {
        try {
            JedisPoolConfig config = new JedisPoolConfig();
            config.setMaxTotal(MAX_TOTAL);
            config.setMaxIdle(MAX_IDLE);
            config.setMaxWaitMillis(MAX_WAIT);
            config.setTestOnBorrow(TEST_ON_BORROW);
            jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 获取Jedis实例
     * @return
     */
    public synchronized static Jedis getJedis() {
        try {
            if (jedisPool != null) {
                Jedis jedis = jedisPool.getResource();
                return jedis;
            } else {
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    /**
     * 释放jedis资源
     * @param jedis
     */
    public static void returnResource(final Jedis jedis) {
        if (jedis != null) {
            jedisPool.returnResource(jedis);
        }
    }
}

3)进行Redis测试

接下来就可以进行测试了。一般我们都是用Junit测试工具来测试:测试部分代码如下

 @Test
       public void testRedisPool() {
             RedisUtils.getJedis().set("xiaomin", ”12122“);
            System.out.println(RedisUtils2.getJedis().get("xiaomin"));
        } 

当然了Redis 还能操作List, Set,SortSeted,Hash等数据类型的数据。

 

四. 综合案例

【参考 http://bigdata.51cto.com/art/201705/539015.htm 链接 】

配置使用redis

项目的整体结构如下:

JavaWeb--------Java实现Redis缓存_第6张图片

在applicationContext-dao.xml中配置如下:

   
     
   
       
           
       
               
               
               
               
           
           
       
            
            
            
            
       
            
           
           
           
       
       
               
               
               
               
               
       
   
   

database.properties配置文件如下:

redis.maxIdle=10   
redis.maxActive=20   
redis.maxWait=10000   
redis.testOnBorrow=true   
redis.host=192.168.1.76   
redis.port=6379   
redis.pass=password1   

spring-data-redis提供了多种serializer策略,这对使用jedis的开发者而言,实在是非常便捷。sdr提供了4种内置的serializer:
JdkSerializationRedisSerializer:使用JDK的序列化手段(serializable接口,ObjectInputStrean,ObjectOutputStream),数据以字节流存储,POJO对象的存取场景,使用JDK本身序列化机制,将pojo类通过ObjectInputStream/ObjectOutputStream进行序列化操作,最终redis-server中将存储字节序列,是目前最常用的序列化策略。
StringRedisSerializer:字符串编码,数据以string存储,Key或者value为字符串的场景,根据指定的charset对数据的字节序列编码成string,是“new String(bytes, charset)”和“string.getBytes(charset)”的直接封装。是最轻量级和高效的策略。
JacksonJsonRedisSerializer:json格式存储,jackson-json工具提供了javabean与json之间的转换能力,可以将pojo实例序列化成json格式存储在redis中,也可以将json格式的数据转换成pojo实例。因为jackson工具在序列化和反序列化时,需要明确指定Class类型,因此此策略封装起来稍微复杂。【需要jackson-mapper-asl工具支持】

OxmSerializer:xml格式存储,提供了将javabean与xml之间的转换能力,目前可用的三方支持包括jaxb,apache-xmlbeans;redis存储的数据将是xml工具。不过使用此策略,编程将会有些难度,而且效率最低;不建议使用。【需要spring-oxm模块的支持】

其中JdkSerializationRedisSerializer和StringRedisSerializer是最基础的序列化策略,其中“JacksonJsonRedisSerializer”与“OxmSerializer”都是基于stirng存储,因此它们是较为“高级”的序列化(最终还是使用string解析以及构建java对象)。 针对“序列化和发序列化”中JdkSerializationRedisSerializer和StringRedisSerializer是最基础的策略,原则上,我们可以将数据存储为任何格式以便应用程序存取和解析(其中应用包括app,hadoop等其他工具),不过在设计时仍然不推荐直接使用“JacksonJsonRedisSerializer”和“OxmSerializer”,因为无论是json还是xml,他们本身仍然是String。如果你的数据需要被第三方工具解析,那么数据应该使用StringRedisSerializer而不是JdkSerializationRedisSerializer。

RedisTemplate中需要声明4种serializer,默认为“JdkSerializationRedisSerializer”:

 

1)keySerializer :对于普通K-V操作时,key采取的序列化策略
2) valueSerializer:value采取的序列化策略
3) hashKeySerializer: 在hash数据结构中,hash-key的序列化策略

 

4) hashValueSerializer:hash-value的序列化策略

无论如何,建议key/hashKey采用StringRedisSerializer。

spring-data-redis针对jedis提供了如下功能:
1. 连接池自动管理,提供了一个高度封装的“RedisTemplate”类
2. 针对jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口
ValueOperations:简单K-V操作
SetOperations:set类型数据操作
ZSetOperations:zset类型数据操作
HashOperations:针对map类型的数据操作
ListOperations:针对list类型的数据操作
3. 提供了对key的“bound”(绑定)便捷化操作API,可以通过bound封装指定的key,然后进行一系列的操作而无须“显式”的再次指定Key,即BoundKeyOperations:

        BoundValueOperations
        BoundSetOperations
        BoundListOperations
        BoundSetOperations

        BoundHashOperations

RedisTemplate的使用

这个类作为一个模版类,提供了很多快速使用redis的api,而不需要自己来维护连接,事务。最初的时候,我创建的BaseRedisDao是继承自这个类的。继承的好处是我的每个Dao中,都可以自由的控制序列化器,自由的控制自己是否需要事务,这个先不需要了解,跟着我目前的这种配置方法来即可。template提供了一系列的operation,比如valueOperation,HashOperation,ListOperation,SetOperation等,用来操作不同数据类型的Redis。并且,RedisTemplate还提供了对应的*OperationsEditor,用来通过RedisTemplate直接注入对应的Operation。

核心代码:

package com.npf.dao.impl;   
   
import java.util.ArrayList;   
import java.util.List;   
import java.util.Map;   
import java.util.Map.Entry;   
   
import javax.annotation.Resource;   
   
import org.springframework.beans.factory.annotation.Autowired;   
import org.springframework.data.redis.core.HashOperations;   
import org.springframework.data.redis.core.RedisTemplate;   
import org.springframework.stereotype.Repository;   
   
import com.npf.dao.StudentDao;   
import com.npf.model.Student;   
   
@Repository   
public class StudentDaoImpl implements StudentDao{   
   
    @Autowired   
    private RedisTemplate redisTemplate;   
       
    @Resource(name="redisTemplate")   
    private HashOperations opsForHash;   
       
    public static final String STUDENT = "student";   
       
    @Override   
    public void save(Student student) {   
        opsForHash.put(STUDENT, student.getId(), student);   
    }   
   
    @Override   
    public Student find(String id) {   
        Student student = opsForHash.get(STUDENT, id);   
        return student;   
    }   
   
    @Override   
    public void delete(String id) {   
        opsForHash.delete(STUDENT, id);   
    }   
   
    @Override   
    public void update(Student student) {   
        opsForHash.put(STUDENT, student.getId(), student);   
    }   
   
    @Override   
    public List findAll() {   
        Map entries = opsForHash.entries(STUDENT);   
        List stuList = new ArrayList();   
        for(Entry entry : entries.entrySet()){   
            stuList.add(entry.getValue());   
        }   
        return stuList;   
    }   
}   

控制层代码如下:

package com.npf.controller;   
   
import java.util.List;   
import java.util.UUID;   
   
import org.springframework.beans.factory.annotation.Autowired;   
import org.springframework.stereotype.Controller;   
import org.springframework.ui.Model;   
import org.springframework.web.bind.annotation.RequestMapping;   
import org.springframework.web.bind.annotation.RequestParam;   
   
import com.npf.model.Student;   
import com.npf.service.StudentService;   
   
@Controller   
public class StudentController {   
   
    @Autowired   
    private StudentService studentService;   
       
    @RequestMapping("/student/save")   
    public String saveStudent(Student student){   
        String id = UUID.randomUUID().toString();   
        System.out.println(id);   
        student.setId(id);   
        studentService.save(student);   
        return "redirect:/student/find/all";   
    }   
       
    @RequestMapping("/student/update")   
    public String updateStudent(Student student){   
        studentService.update(student);   
        return "redirect:/student/find/all";   
    }   
       
    @RequestMapping("/student/to/save/form")   
    public String toSaveStudentForm(){   
        return "save";   
    }   
       
    @RequestMapping("/student/delete")   
    public String deleteStudent(@RequestParam("id") String id){   
        studentService.delete(id);   
        return "redirect:/student/find/all";   
    }   
       
    @RequestMapping("/student/to/update/form")   
    public String toUpdateStudentForm(@RequestParam("id") String id,Model model){   
        Student stu = studentService.find(id);   
        model.addAttribute("stu", stu);   
        return "update";   
    }   
       
    @RequestMapping("/student/find/all")   
    public String findStudents(Model model){   
        List stuList = studentService.findAll();   
        model.addAttribute("stuList", stuList);   
        return "list";   
    }   
}   

 

 

-----------------------------------------------  我是低调的分隔线  -----------------------------------------------

 

你可能感兴趣的:(编程)