Redis客户端之Jedis,SpringBoot中使用StringRedisTemplate,通过注解的方式简单操作以及连接池的配置

简介:

其实就是一个基于java语言的redis-cli客户端。

Redis是一种运行在内存当中键值数据库,而且是以字符串类型为中心的,当前它能够支持多重数据类型,包括字符串,
散列,列表,集合,有序集合,基数和地理位置等。

在Spring项目当中使用Redis:
    我们需要通过连接池创建一个RedisConnectionFactory对象,通过它我们就能够创建RedisConnection接口对象,
    但是当我们使用一条连接时,我们要先从RedisConnectionFactory工厂获取,然后在使用完成后还要自己去关闭。
    Spring为简化操作,提供RedisTemplate
redisTemplate.opsForvalue().set("key1","value1");当存储这样的一对键值对时,从Redis客户端输入
key*key1,得到的并不是value1。因为Redis是基于字符串存储的NoSQl,而java是基于对象的语言,对象是无法储存到
Redis中的,不过java中提供了序列化机制,可以将对象转换成二进制字符串。
所以就有了Redis键序列化器,

RedisSerializer stringRedisSerializer=redisTemplate.getStringSerializer;

设置后能够从复杂的编码得到简单的字符串。

在SpringBoot中使用Redis:
1.首先要在官网下载Redis,添加服务到本地,(设置开机自动启动该服务)
2.导入依赖
        <!--Redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
3.导入依赖后,SpringBoot已将帮我把RedisTemplateFactory,RedisTemplate,StringRedisTemplate
的常用对象添加到IOC容器当中,因此我们只需要从IOC容器中获取该对象即可。
可以通过 redis-cli.exe -h 127.0.0.1 -p 6379命令查找key对应的value和设置键值对

Redis的一些特殊用法:
    Redis除了操作那些数据类型的功能外,还能支持事务,流水线,发布订阅和Lua语等功能
    在高并发的场景中,往往我们需要保证数据的一致性,这是考虑使用Redis事务,或者是利用Redis执行
    Lua的原子性来达到数据一致性的目的。
使用Redis事务:
    在Redis中使用事务,通常的命令组合是watch,multi,exec。也就是要在一个Redis连接中执行多个命令,
    这时我们可以考虑使用SessionCallBack来达到这个目的。
watch:是可以监控Redis的一些键;
multi:是开始事务,开启事务后,该客户端的命令不会马上立即被执行,而是存放在一个队列中,结果返回null
exec:执行事务,只是他在队列命令执行前会判断被watch监控的Redis的键的数据是否发生过改变,如果他认为发生了
改变,(即使是相同的值覆盖也认为是改变)那么Redis就会取消事务。
测试代码:

1.SpringBoot中对Redis中String类型的使用

依赖:

<!--添加mysql驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.37</version>
</dependency>
<!--添加DBCP数据源-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
</dependency>
<!--Redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

常用配置 :

# REDIS (RedisProperties)
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
# 添加redis到服务 redis-server --service-install redis.windows.conf
# 开启服务 redis-server --service-start
spring.redis.port=6379
# 默认无密码
spring.redis.password=
spring.redis.jedis.pool.max-active=10
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.max-wait=2000ms
spring.redis.jedis.pool.min-idle=5


#缓存管理器配置
#如果底层的缓存管理器支持创建,以逗号分隔列表缓存名称
spring.cache.cache-names=redisCache
#是否允许Redis缓存空值
spring.cache.redis.cache-null-values=true
#Redis的键前缀
spring.cache.redis.key-prefix=
#缓存超时时间戳,配置为0则不设置超时时间 十分钟
spring.cache.redis.time-to-live=600000ms
#是否启用Redis的键前缀
spring.cache.redis.use-key-prefix=true
# 缓存类型 默认情况下,Spring会自动根据上下文探测
spring.cache.type=REDIS

控制层:

@Controller
@RequestMapping("/redis")
public class RedisController {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @RequestMapping("/stringAndHash")
    @ResponseBody
    public Map<String,Object> testStringAndHash(){
        redisTemplate.opsForValue().set("key1","value1");
        //默认使用JDK的序列化器,所以Redis保存的不是整数,不能进行运行
        redisTemplate.opsForValue().set("int_key1","1");
        //使用运算
        stringRedisTemplate.opsForValue().set("int","1");
        //获取底层Redis连接
//        RedisProperties.Jedis jedis;
//        jedis= (RedisProperties.Jedis) stringRedisTemplate.getConnectionFactory().getConnection().getNativeConnection();
//        jedis.

        //减一操作 redisTemplate不支持
        Map<String,String> hash=new HashMap();
        hash.put("field1","value1");
        hash.put("field2","value2");
        //存入一个散列数据类形
        stringRedisTemplate.opsForHash().putAll("hash",hash);
        stringRedisTemplate.opsForHash().put("hash","field3","value3");
        //绑定散列操作的key,这样可以连续对一个散列数据类型进行操作
        BoundHashOperations hashOps=  stringRedisTemplate.boundHashOps("hash");
        hashOps.delete("field1","field2");
        hashOps.put("field4","value4");
        Map map=new HashMap();
        map.put("Success",true);
        return map;
    }


    @Autowired
    private MybatisUserService mybatisUserService;
    @RequestMapping("/insertUser")
    @ResponseBody
    public User insertUser(){
        User user=new User();
        user.setName("redis");
        user.setNote("新成员");
        mybatisUserService.insertUser(user);
        return user;
    }
    @RequestMapping("/findUser")
    @ResponseBody
    public User findUser(int id)
    {
        return mybatisUserService.findUser(id);
    }

    @RequestMapping("/updateUser")
    @ResponseBody
    public User updateUser(Integer id,String name){
        return mybatisUserService.updateUser(id,name);
    }

    @RequestMapping("/deleteUser")
    @ResponseBody
    public int deleteUser(Integer id){
         return mybatisUserService.deleteUser(id);
    }
}

组件 :

@Component
public class RedisComponent {
    //通过stringRedisTemplate进行序列化键值,这样只能支持支持字符串,并不能支持java对象的储存。
    //不设置时,RedisTemplate默认使用JdkSerializationRedisSerializer 进行序列化键值。存储到
    //服务器,这是存入的便是一个经过序列化后的特殊字符,对于我们跟踪不友好!
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public void set(String key,String value){
        //拿到存储操作对象
        ValueOperations<String,String> ops=stringRedisTemplate.opsForValue();
        if(stringRedisTemplate.hasKey(key))
        {
            System.out.println("Key="+key+"value="+value);
        }
        else{
            ops.set(key, value);
            System.out.println("添加成功!");
        }
    }
    public String get(String key){

        return stringRedisTemplate.opsForValue().get(key);
    }
    public void delete(String key){
        stringRedisTemplate.delete(key);
        System.out.println("删除成功!");
    }

}

业务层

//插入用户,最后Mybatis会回填ID,取结果id缓存用户
@Override
@Transactional
@CachePut(value = "redisCache",key = "'redis_user_'+#result.id")
//当方法返回值为int类型时会报找不到id异常
//value配置对应缓存名称redisCache 键配置:#result表示返回对象user
//而且返回类型必须为User不然会报异常
public User insertUser(User user) {
     mybatisUserDao.insertUser(user);
     return user;
}

@Override
@Transactional
@CachePut(value = "redisCache",key = "'redis_user_'+#result.id",condition = "#result!='null'")
//如果返回结果为空,则不使用缓存
public User updateUser(Integer id,String name) {
    User user=this.findUser(id);//该方法的缓存注解在此处会失效
    if(user==null)
    {
        System.out.println("查找用户失败!!!");
        return null;
    }
    user.setName("更改后的名字");
    user.setNote("更改后的身份");
    mybatisUserDao.updateUser(user);//不要忘了。。
    return user;
}

@Override
@Transactional
@Cacheable(value = "redisCache" ,key = "'redis_user_'+#id")
//参数中不是User对象不能设置为#result.id
public User findUser(Integer id) {
    return mybatisUserDao.findUser(id);
}

@Override
@Transactional
@CacheEvict(value = "redisCache",key ="'redis_user_'+#id",beforeInvocation = false)
//默认值为false 表示在该方法之后移除缓存
public int deleteUser(Integer id) {
    return mybatisUserDao.deleteUser(id);
}

2.Jedis总结:

# Jedis直连

## 执行流程

1. 创建Jedis对象

Jedis jedis=new Jedis("127.0.0.1",6379);
2. 通过Jedis执行命令
3. 返回Jedis执行结果
4. 关闭Jedis连接

## 创建Jedis的方式

```java
/**
 *    @param host Redis节点所在机器的IP或域名
 *  @param port Redis服务的端口号
 *  @param connectionTimeout 客户端连接超时时间(毫秒)
 *  @param soTimeout 客户端读写超时时间(毫秒)
 */
public Jedis(String host , int port , int connectionTimeout , int soTimeout)
```

具体参考API文档http://tool.oschina.net/apidocs/apidoc?api=jedis-2.1.0

 

# Jedis连接池

## 执行流程

1. 创建一个JedisPool对象
2. 从资源池中获取一个Jedis对象
3. 通过Jedis执行命令
4. 返回Jedis执行结果
5. 关闭Jedis连接,将Jedis还给资源池

## 创建Jedis连接池的方式

```java
JedisPoolConfig config = new JedisPoolConfig();
JedisPool jedisPool = new JedisPool(config , "127.0.0.1" , 6379);
Jedis jedis = jedisPool.getResource();
jedis.close();
```

最好是使用try catch方式

 

# Jedis直连 VS Jedis连接池

|             |                             优点                             |                             缺点                             |
| :---------: | :----------------------------------------------------------: | :----------------------------------------------------------: |
|  Jedis直连  |            使用简单<br/>适用于少量长期连接的场景             | 存在每次新建/关闭TCP连接的开销<br/>资源无法控制,存在连接泄露的风险<br/>Jedis对象线程不安全 |
| Jedis连接池 | Jedis对象预先生成,降低使用开销<br/>连接池的形式保护和控制资源的使用 | 相对于直连,使用相对麻烦<br/>尤其在资源的管理上需要许多参数保证<br/>一旦参数不合理会出现很多问题 |

Jedis连接池配置

1.commons-pool资源数配置参数:

2.commons-pool借还参数

JedisPoolConfig jedisPoolConfig=new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(10);
jedisPoolConfig.setMaxWaitMillis(1000);

JedisPool jedisPool=new JedisPool(jedisPoolConfig,"127.0.0.1",6379);

for(int i=0;i<10;i++){
    Jedis jedis=null;
    try {
        jedis=jedisPool.getResource();
        System.out.println(jedis.ping()+(i+1));
    }catch (Exception e){
        e.printStackTrace();
    }finally {
    jedis.close();
        //当我们不在finally中进行资源的关闭时,
        // 由于连接池中的jedis都在被使用,就会出现连接超时的错误
    }
}
jedisPool.getResource().ping();

复杂一点的jedis连接池配置。https://blog.csdn.net/u010473656/article/details/78838254

在springboot中配置参考上文很简单。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值