spring-boot-note6---redis

野生技術協會發表於2021-01-03

SpringBoot整合Redis,本文采用RedisTemplate操作redis和配置CacheMannager使用快取註解的二個方式。

一、配置相關

  1、新增pom依賴

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-redis</artifactId>
        </dependency>

2、application.properties

#redis配置
spring.redis.database=0
#Redis伺服器地址
spring.redis.host=127.0.0.1
#Redis伺服器連線埠
spring.redis.port=6379
#Redis伺服器連線密碼(預設為空)
spring.redis.password=123456
#連線超時時間
spring.redis.timeout=2000
#連線池最大連線數(使用負值表示沒有限制)
spring.redis.pool.max-active=500
#連線池最大阻塞等待時間(使用負值表示沒有限制)
spring.redis.pool.max-wait=10000
#連線池中的最大空閒連線
spring.redis.pool.max-idle=50
#連線池中的最小空閒連線
spring.redis.pool.min-idle=0

 包結構: 

配置類詳細:(1、配置redisTemplate可直接操作redis,2、配置CacheManager+@EnableCaching可以使用快取註解)

@Configuration
@EnableCaching  // 開啟註解的方式
public class RedisConfig {
	
	
    /**
     * 1、設定CacheManager實現為redisCacheMannager,並且開啟EnableCaching,可以使用快取註解。
     */
    @Bean
    public CacheManager cacheManager(RedisTemplate<?, ?> redisTemplate) {
        RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
        rcm.setUsePrefix(true);
        rcm.setCacheNames(Arrays.asList("myCache"));
        rcm.setDefaultExpiration(600);
        return rcm;
    }
    
    /**
     * 2、redisTemplate配置完成可以直接使用redis
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);

        //使用Jackson2JsonRedisSerializer來序列化和反序列化redis的value值(預設使用JDK的序列化方式)
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, Visibility.ANY);
        mapper.enableDefaultTyping(DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(mapper);

        //使用StringRedisSerializer來序列化和反序列化redis的key值
        template.setValueSerializer(serializer);
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(serializer);
        template.afterPropertiesSet();
        return template;
    }

二、使用redistemplate操作redis

1、pojo、dao等。

public class Person implements Serializable{
	private static final long serialVersionUID = -3189329947019478591L;
	private Integer id;
	public String name;
@Component
public class PersonDao {
	
	private static Map<Integer, Person> map = new HashMap<>();
	
	static {
		Person p;
		for (int i = 0; i < 10; i++) {
			p = new Person();
			p.setId(i);
			p.setName("name" + i);
			map.put(i, p);
		}
	}
	
	public void deleteById(Integer id) {
		map.remove(id);
	}
	
	public Person findById(Integer id) {
		return map.get(id);
	}
	
	public void updateOne(Person person) {
		Person old = map.get(person.getId());
		old.setName(person.getName());
	}

	public void saveOne(Person person) {
		map.put(person.getId(), person);
	}

	public List<Person> findList() {
		return new ArrayList<>(map.values());
	}

2、redisTemplate操作redis的service類

/**
 * 使用redisTemplate操作快取。
 */
@Service
public class PersonService {
	
	 private Logger logger = LoggerFactory.getLogger(this.getClass());

	@Autowired
	private PersonDao personDao;
	
	@Resource
	private RedisTemplate<String, Person> redisTemplate;
	
	/**
	 * 查詢person
	 * 快取存在從快取中取,不存在,查詢出放入快取。
	 */
	public Person getById(int id) {
		logger.info("獲取使用者start...");
		String key = "person_" + id;
		ValueOperations<String, Person> operations = redisTemplate.opsForValue();
		boolean hasKey = redisTemplate.hasKey(key);
		if (hasKey) {
			Person user = operations.get(key);
			logger.info("從快取中獲取了 id = " + id);
			return user;
		}
		Person person = personDao.findById(id);
		operations.set(key, person, 10, TimeUnit.SECONDS);
		return person;
	}
	
    /**
     * 更新使用者
     * 如果快取存在,刪除
     * 如果快取不存在,不操作
     */
    public void updateUser(Person person) {
        logger.info("更新使用者start...");
        personDao.updateOne(person);
        String key = "person_" + person.getId();
        boolean hasKey = redisTemplate.hasKey(key);
        if (hasKey) {
            redisTemplate.delete(key);
            logger.info("更新時,刪除快取id= " + person.getId());
        }
    }
	
    /**
     * 刪除使用者
     * 如果快取中存在,刪除
     */
	public void deleteById(int id) {
		logger.info("刪除使用者start...");
		personDao.deleteById(id);
		String key = "person_" + id;
		boolean hasKey = redisTemplate.hasKey(key);
		if (hasKey) {
			redisTemplate.delete(key);
			logger.info("刪除時,從快取中刪除id=>> " + id);
		}
	}

}

3、測試使用。

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class TestPersonService {
	
	 @Autowired
	 private PersonService personService;

	/**
	 * redis快取使用redisTemplate操作的演示
	 */
	@Test
	public void testCache() {
		int id = 1;
		Person person = personService.getById(id);  // 第1次查詢           //獲取使用者start...
		Person person2 = personService.getById(id); // 第2次查詢         //獲取使用者start... 
																    //從快取中獲取了 id = 1
		person2.setName("update_name");
		personService.updateUser(person2); // 第1次更新  				//更新使用者start... 
												       				//更新時,刪除快取id= 1
		Person person3 = personService.getById(id); // 第3次查詢  	//獲取使用者start...
		System.out.println(person3.getName()); 						// update_name
		personService.deleteById(id); // 第1次刪除   					// 刪除使用者start... 
									  								// 刪除時,從快取中刪除id=>> 1
		assertNull(personService.getById(id));
	}
	
}

三、使用快取註解的方式。

@Service
public class PersonCacheService {
	
	@Autowired
	private PersonDao personDao;
	
	/**
	 * 查詢一個Person
	 */
	@Cacheable(value = "myCache", key = "'Persons_'+#id")
	public Person findPerson(Integer id) {
		Person person = this.personDao.findById(id);
		System.out.println("資料庫查一條記錄:id=" + id);
		return person;
	}
	
	/**
	 * 更新一個Person,每次都會執行。
	 */
	@CachePut(value="myCache", key="'Persons_'+#id")
	public Person updatePerson(Person person,Integer id) {
		this.personDao.updateOne(person);
		System.out.println("資料庫更新一條記錄:id=" + id);
		return person;
		
	}

	/**
	 * 刪除一個Person
	 */
	@CacheEvict(value = "myCache", key = "'Persons_'+#id", condition = "#id!=99")
	public void delPerson(Integer id) {
		System.out.println("資料庫刪除一條記錄:id=" + id);
		this.personDao.deleteById(id);
	}
	
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class TestPersonCacheService {

	 @Autowired
	 private PersonCacheService personCacheService;
	
	 @Test
	 public void test1() {
		Person person1 = personCacheService.findPerson(1); // 資料庫查一條記錄:id=1
		Person person2 = personCacheService.findPerson(1);
		person2.setName("update_name");
		personCacheService.updatePerson(person2, 1); //資料庫更新一條記錄:id=1
		Person person3 = personCacheService.findPerson(1); // 不查詢,@CachePut每次都會執行,並把結果放入快取。
		System.out.println(person3.getName()); //update_name
		personCacheService.delPerson(1); // 資料庫刪除一條記錄:id=1
	 }

}