赞
踩
其实就是一个基于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就会取消事务。
- 测试代码:
依赖:
- <!--添加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); }
# 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/>一旦参数不合理会出现很多问题 |
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中配置参考上文很简单。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。