注意:阿里云要在redis.conf中开启:才能进行java连接redis
protected-mode no 关闭protected-mode模式,此时外部网络可以直接访问
注意:这里要用公网ip
Jedis jedis=new Jedis("192.168.213.122",6379);//必须运行远程连接 必须防火墙放行该端口号
依赖:
<dependencies>
<dependency>
<groupId>redis.clientsgroupId>
<artifactId>jedisartifactId>
<version>3.3.0version>
dependency>
dependencies>
测试代码:
@Test
public void test1() {
// 必须运行远程连接,必须防火墙放行该端口号
Jedis jedis = new Jedis("8.140.7.46", 6378);
// 关于字符串
jedis.set("k1", "v1");
jedis.set("k2", "v2");
System.out.println(jedis.setnx("k1", "v1"));
// 操作key
Set<String> keys = jedis.keys("*");
System.out.println(keys);
jedis.del("k2");
jedis.expire("k2",60);
System.out.println(jedis.ttl("k2"));
}
//连接池的配置
JedisPoolConfig config=new JedisPoolConfig();
config.setMaxTotal(100);//设置连接池的最大连接数
config.setMaxIdle(10);//设置最大空闲的个数
config.setTestOnBorrow(true);//在从连接池这种获取连接对象前是否测试该对象可以。
//创建连接池对象
JedisPool jedisPool=new JedisPool(config,"192.168.213.188",6379);
//获取jedis对象
Jedis jedis = jedisPool.getResource();
System.out.println(jedis.get("k3"));
jedis.close();//释放资源
springboot为操作redis准备了两个工具类StringRedisTemplate和RedisTemplate。StringRedisTemplate是RedisTemplate的子类。StringRedisTemplate它的泛型key和value都是String类型。 RedisTemplate它的key value的泛型是Object。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
阿里云在这里要写公网ip
spring.redis.host=192.168.213.188
spring.redis.port=6379
spring.redis.jedis.pool.max-active=20
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.min-idle=0
spring.redis.jedis.pool.max-wait=20000
在这里注入的是StringRedisTemplate
@Test
void contextLoads() {
// 操作key
Set<String> keys = stringRedisTemplate.keys("*");
System.out.println(keys);
stringRedisTemplate.delete("k1");
System.out.println(stringRedisTemplate.getExpire("k3"));
// 设置过期时间
stringRedisTemplate.expire("k3",60, TimeUnit.SECONDS);
System.out.println(stringRedisTemplate.getExpire("k3"));
}
@Test
public void testString(){
// 对字符串操作的
ValueOperations<String, String> forValue = stringRedisTemplate.opsForValue();
forValue.set("k1","v1");
System.out.println(forValue.get("k1"));
HashMap<String, String> map = new HashMap<>();
map.put("k9","v9");
map.put("k10","v10");
// 相当于 mset 一次存放多个字符串的value到响应的key上
forValue.multiSet(map);
ArrayList<String> list = new ArrayList<>();
list.add("k1");
list.add("k1");
list.add("k2");
List<String> list1 = forValue.multiGet(list);
System.out.println(list1);
// 相当于setnx 把指定的value存放到对应的key上,如果对应的key已经存在,咋不存储,如果不存在,则存储。
System.out.println(forValue.setIfAbsent("K2","V2"));
}
使用redisTemplate该类可以存放任意类型的数据,但是该类型的数据必须实现序列,获取redis中对应的数据时,会进行反序列化。 如果使用RedisTemplate建议大家指定key,value,以及hashkey的序列化方式。
在这里可以用于验证码,给key,value设置序列化方式,配置序列化(解决乱码的问题)
@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
//比如验证码
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
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);
template.setConnectionFactory(factory);
//key序列化方式
template.setKeySerializer(redisSerializer);
//value序列化
template.setValueSerializer(jackson2JsonRedisSerializer);
//value hashmap序列化
template.setHashValueSerializer(jackson2JsonRedisSerializer);
return template;
}
@Bean
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);
// 配置序列化(解决乱码的问题),过期时间600秒
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(600)) //缓存过期10分钟 ---- 业务需求。
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))//设置key的序列化方式
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)) //设置value的序列化
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
return cacheManager;
}
}
(1)在idea中application.properties文件添加哨兵代码
spring.redis.sentinel.master=mymaster
spring.redis.sentinel.nodes=192.168.213.188:26379
注意:这里的ip要为外网ip,即服务器的公网ip
(2)连接普通的redis,阿里云这里要填公网ip
spring.redis.host=8.140.7.42
spring.redis.port=6378
(1) 在idea中application.properties文件添加去中心化集群代码
端口号
server.port=8888
spring.redis.cluster.nodes= 192.168.213.188:8001,192.168.213.188:8002,192.168.213.188:8003,192.168.213.188:8004,192.168.213.188:8005,192.168.213.188:8006
(2)搭建去中心化集群,分配槽写8001,阿里云服务器的安全组要放行12个端口8001,8002,8003,8004,8005,8006,18001,18002,18003,18004,18005,18006。因为它默认要加上10000
以下是官网的解释:
1.为什么使用缓存?
减少数据库的访问频率。 提高数据的访问率。
2.什么样的数据适合放入缓存?
1.热点数据。 2. 修改频率比较低。3.安全系数低的。
如何使用缓存
(1)搭建一个springboot+mp的工程
(2)引入redis相关的依赖
(3)配置redis
(4)service实现类代码
@Service
public class DeptServiceI {
@Resource
private DeptDao deptDao;
@Autowired
private RedisTemplate redisTemplate;
public Dept findById(Integer deptId){
//1.从缓存中查询该数据
Object o = redisTemplate.opsForValue().get("findById::" + deptId);
if(o!=null){//表示从缓存中获取该数据
return (Dept) o;
}
Dept dept = deptDao.selectById(deptId);
redisTemplate.opsForValue().set("findById::"+deptId,dept);//把查询的结果放入缓存
return dept;
}
//数据库和缓存同步问题!
public int delete(Integer deptId){
redisTemplate.delete("findById::"+deptId);//删除缓存
int i = deptDao.deleteById(deptId);
return i;
}
public int update(Dept dept){
redisTemplate.delete("findById::"+dept.getDeptId());//删除缓存
int i = deptDao.updateById(dept);
redisTemplate.opsForValue().set("findById::"+dept.getDeptId(),dept);
return i;
}
}
上面这些代码每次都要写很多与业务无关的一些非业务代码!
(1)使用aop来解决---->动态代理(动态代理的实现模式基于JDK动态代理)
https://blog.csdn.net/qq_39470733/article/details/77315010
(2)基于spring的缓存注解。
@Cacheable(cacheNames = “findById”,key = “#deptId”) //缓存的key值 为findById,用于查询的方法。
该注解作用:会先查询缓存,如果缓存存在,则不会执行代码块。 如果缓存中不存在则执行该方法,并把该方法的返回值存放到redis中
@CacheEvict(cacheNames = “findById”,key = “#deptId”),用于删除的方法。
如果指定为 true,则在方法还没有执行的时候就清空缓存。缺省情况下,如果方法执行抛出异常,则不会清空缓存。
@CachePut(cacheNames = “findById”,key = “#dept.deptId”),用于修改的方法。
这个注解是必须执行方法体,而且会把方法体执行的结果放入到缓存中。 如果发生异常则不操作缓存。
(1)在启动类添加这个开启缓存的注解
@EnableCaching //开启缓存的注解
(2)service实现类代码
@Service
public class DeptService {
@Resource
private DeptDao deptDao;
//该注解作用:会先查询缓存,如果缓存存在,则不会执行代码块。 如果缓存中不存在则执行该方法,并把该方法的返回值存放到redis中
@Cacheable(cacheNames = "findById",key = "#deptId") //缓存的key值 为findById
public Dept findById(Integer deptId){
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
Dept dept = deptDao.selectById(deptId);
return dept;
}
//数据库和缓存同步问题!
// beforeInvocation:是否在方法执行前就清空,缺省为 false,
// 如果指定为 true,则在方法还没有执行的时候就清空缓存。缺省情况下,如果方法执行抛出异常,则不会清空缓存。
@CacheEvict(cacheNames = "findById",key = "#deptId")
public int delete(Integer deptId){
int i = deptDao.deleteById(deptId);
return i;
}
//这个注解是必须执行方法体,而且会把方法体执行的结果放入到缓存中。 如果发生异常则不操作缓存。
@CachePut(cacheNames = "findById",key = "#dept.deptId")
public Dept update(Dept dept){
int i = deptDao.updateById(dept);
return dept;
}
}
见下篇文章