完成springboot-cache
This commit is contained in:
parent
1f6885b8bf
commit
1cb7cdb7b7
@ -16,6 +16,7 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.0.4.RELEASE</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
@ -34,10 +35,10 @@
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
<version>2.9.0</version>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
|
@ -2,8 +2,10 @@ package com.xncoding.trans;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableCaching
|
||||
public class Application {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
|
@ -11,11 +11,14 @@ import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.RedisPassword;
|
||||
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||
@ -37,73 +40,38 @@ import java.util.Map;
|
||||
*/
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
public class RedisCacheConfig extends CachingConfigurerSupport {
|
||||
public class RedisCacheConfig {
|
||||
private Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Value("${spring.redis.host}")
|
||||
private String host;
|
||||
|
||||
@Value("${spring.redis.port}")
|
||||
private String port;
|
||||
@Autowired
|
||||
private Environment env;
|
||||
|
||||
@Bean
|
||||
public RedisStandaloneConfiguration getRedisClient() {
|
||||
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(host, Integer.parseInt(port));
|
||||
return redisStandaloneConfiguration;
|
||||
public LettuceConnectionFactory redisConnectionFactory() {
|
||||
RedisStandaloneConfiguration redisConf = new RedisStandaloneConfiguration();
|
||||
redisConf.setHostName(env.getProperty("spring.redis.host"));
|
||||
redisConf.setPort(Integer.parseInt(env.getProperty("spring.redis.port")));
|
||||
redisConf.setPassword(RedisPassword.of(env.getProperty("spring.redis.password")));
|
||||
return new LettuceConnectionFactory(redisConf);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JedisConnectionFactory redisConnectionFactory(RedisStandaloneConfiguration RedisStandaloneConfiguration) {
|
||||
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(RedisStandaloneConfiguration);
|
||||
return jedisConnectionFactory;
|
||||
public RedisCacheConfiguration cacheConfiguration() {
|
||||
RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig()
|
||||
.entryTtl(Duration.ofSeconds(600))
|
||||
.disableCachingNullValues();
|
||||
return cacheConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf) {
|
||||
RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
|
||||
redisTemplate.setConnectionFactory(cf);
|
||||
return redisTemplate;
|
||||
public RedisCacheManager cacheManager() {
|
||||
RedisCacheManager rcm = RedisCacheManager.builder(redisConnectionFactory())
|
||||
.cacheDefaults(cacheConfiguration())
|
||||
.transactionAware()
|
||||
.build();
|
||||
return rcm;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RedisCacheConfiguration redisCacheConfiguration() {
|
||||
return RedisCacheConfiguration
|
||||
.defaultCacheConfig()
|
||||
.serializeKeysWith(
|
||||
RedisSerializationContext
|
||||
.SerializationPair
|
||||
.fromSerializer(new StringRedisSerializer()))
|
||||
.serializeValuesWith(
|
||||
RedisSerializationContext
|
||||
.SerializationPair
|
||||
.fromSerializer(new GenericJackson2JsonRedisSerializer()))
|
||||
.entryTtl(Duration.ofSeconds(600L));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CacheManager cacheManager(RedisConnectionFactory cf) {
|
||||
//RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(cf);
|
||||
//RedisCacheManager cacheManager = new RedisCacheManager(redisCacheWriter, RedisCacheConfiguration.defaultCacheConfig());
|
||||
RedisCacheManager cm = RedisCacheManager.builder(cf).cacheDefaults(redisCacheConfiguration()).build();
|
||||
return cm;
|
||||
}
|
||||
|
||||
// @Bean
|
||||
// public KeyGenerator keyGenerator() {
|
||||
// return new KeyGenerator() {
|
||||
// @Override
|
||||
// public Object generate(Object o, Method method, Object... objects) {
|
||||
// StringBuilder sb = new StringBuilder();
|
||||
// sb.append(o.getClass().getName());
|
||||
// sb.append(method.getName());
|
||||
// for (Object obj : objects) {
|
||||
// sb.append(obj.toString());
|
||||
// }
|
||||
// return sb.toString();
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
|
||||
/**
|
||||
* 自定义缓存key的生成类实现
|
||||
*/
|
||||
|
@ -1,19 +1,19 @@
|
||||
package com.xncoding.trans.service;
|
||||
|
||||
import com.baomidou.mybatisplus.mapper.Condition;
|
||||
import com.xncoding.trans.dao.entity.User;
|
||||
import com.xncoding.trans.dao.repository.UserMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.cache.annotation.CacheConfig;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.CachePut;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.cache.annotation.*;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@CacheConfig(cacheNames = "users")
|
||||
@Transactional
|
||||
public class UserService {
|
||||
private Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
@Resource
|
||||
@ -26,78 +26,59 @@ public class UserService {
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@Cacheable(key = "#id")
|
||||
@Cacheable(value = "userCache", key = "#id", unless="#result == null")
|
||||
public User getById(int id) {
|
||||
logger.info("获取用户start...");
|
||||
return userMapper.selectById(id);
|
||||
}
|
||||
|
||||
/***
|
||||
* 如果设置sync=true,
|
||||
* 如果缓存中没有数据,多个线程同时访问这个方法,则只有一个方法会执行到方法,其它方法需要等待
|
||||
* 如果缓存中已经有数据,则多个线程可以同时从缓存中获取数据
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@Cacheable(key = "#id", sync = true)
|
||||
public User getById2(int id) {
|
||||
logger.info("获取用户start...");
|
||||
return userMapper.selectById(id);
|
||||
@Cacheable(value = "allUsersCache", unless = "#result.size() == 0")
|
||||
public List<User> getAllUsers() {
|
||||
logger.info("获取所有用户列表");
|
||||
return userMapper.selectList(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 以上我们使用默认的keyGenerator,对应spring的SimpleKeyGenerator
|
||||
* 如果你的使用很复杂,我们也可以自定义myKeyGenerator的生成key
|
||||
* <p>
|
||||
* key和keyGenerator是互斥,如果同时制定会出异常
|
||||
* The key and keyGenerator parameters are mutually exclusive and an operation specifying both will result in an exception.
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
* 创建用户,同时使用新的返回值的替换缓存中的值
|
||||
* 创建用户后会将allUsersCache缓存全部清空
|
||||
*/
|
||||
@Cacheable(keyGenerator = "myKeyGenerator")
|
||||
public User queryUserById(int id) {
|
||||
logger.info("queryUserById,id={}", id);
|
||||
return userMapper.selectById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次执行都会执行方法,同时使用新的返回值的替换缓存中的值
|
||||
*
|
||||
* @param user
|
||||
*/
|
||||
@CachePut(key = "#user.id")
|
||||
public void createUser(User user) {
|
||||
@Caching(
|
||||
put = {@CachePut(value = "userCache", key = "#user.id")},
|
||||
evict = {@CacheEvict(value = "allUsersCache", allEntries = true)}
|
||||
)
|
||||
public User createUser(User user) {
|
||||
logger.info("创建用户start..., user.id=" + user.getId());
|
||||
userMapper.insert(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次执行都会执行方法,同时使用新的返回值的替换缓存中的值
|
||||
*
|
||||
* @param user
|
||||
* 更新用户,同时使用新的返回值的替换缓存中的值
|
||||
* 更新用户后会将allUsersCache缓存全部清空
|
||||
*/
|
||||
@CachePut(key = "#user.id")
|
||||
public void updateUser(User user) {
|
||||
@Caching(
|
||||
put = {@CachePut(value = "userCache", key = "#user.id")},
|
||||
evict = {@CacheEvict(value = "allUsersCache", allEntries = true)}
|
||||
)
|
||||
public User updateUser(User user) {
|
||||
logger.info("更新用户start...");
|
||||
userMapper.updateById(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对符合key条件的记录从缓存中book1移除
|
||||
* 对符合key条件的记录从缓存中移除
|
||||
* 删除用户后会将allUsersCache缓存全部清空
|
||||
*/
|
||||
@CacheEvict(key = "#id")
|
||||
@Caching(
|
||||
evict = {
|
||||
@CacheEvict(value = "userCache", key = "#id"),
|
||||
@CacheEvict(value = "allUsersCache", allEntries = true)
|
||||
}
|
||||
)
|
||||
public void deleteById(int id) {
|
||||
logger.info("删除用户start...");
|
||||
userMapper.deleteById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* allEntries = true: 清空user1里的所有缓存
|
||||
*/
|
||||
@CacheEvict(allEntries=true)
|
||||
public void clearUser1All(){
|
||||
logger.info("clearAll");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -10,9 +10,9 @@ spring:
|
||||
profiles:
|
||||
active: dev
|
||||
datasource:
|
||||
url: jdbc:mysql://127.0.0.1:3306/test?useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8
|
||||
url: jdbc:mysql://123.207.66.156:3306/test?useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8
|
||||
username: root
|
||||
password: 123456
|
||||
password: _EnZhi123
|
||||
|
||||
################### mybatis-plus配置 ###################
|
||||
mybatis-plus:
|
||||
@ -42,10 +42,22 @@ spring:
|
||||
profiles: dev
|
||||
cache:
|
||||
type: REDIS
|
||||
redis:
|
||||
cache-null-values: false
|
||||
time-to-live: 600000ms
|
||||
use-key-prefix: true
|
||||
cache-names: userCache,allUsersCache
|
||||
redis:
|
||||
host: 123.207.66.156
|
||||
port: 6379
|
||||
database: 0
|
||||
lettuce:
|
||||
shutdown-timeout: 200ms
|
||||
pool:
|
||||
max-active: 7
|
||||
max-idle: 7
|
||||
min-idle: 2
|
||||
max-wait: -1ms
|
||||
|
||||
logging:
|
||||
level:
|
||||
|
@ -7,8 +7,11 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.annotation.Rollback;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@ -24,24 +27,41 @@ import static org.junit.Assert.assertNull;
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = Application.class)
|
||||
@Transactional
|
||||
public class UserServiceTest {
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
@Test
|
||||
public void testCache() {
|
||||
int id = new Random().nextInt(100);
|
||||
// 创建一个用户admin
|
||||
int id = new Random().nextInt(1000);
|
||||
User user = new User(id, "admin", "admin");
|
||||
userService.createUser(user);
|
||||
User user1 = userService.getById(id); // 第1次访问
|
||||
assertEquals(user1.getPassword(), "admin");
|
||||
User user2 = userService.getById(id); // 第2次访问
|
||||
assertEquals(user2.getPassword(), "admin");
|
||||
User user3 = userService.queryUserById(id); // 第3次访问,使用自定义的KeyGenerator
|
||||
|
||||
// 再创建一个用户xiong
|
||||
int id2 = new Random().nextInt(1000);
|
||||
User user2 = new User(id2, "xiong", "neng");
|
||||
userService.createUser(user2);
|
||||
|
||||
// 查询所有用户列表
|
||||
List<User> list = userService.getAllUsers();
|
||||
assertEquals(list.size(), 2);
|
||||
|
||||
// 两次访问看看缓存命中情况
|
||||
User user3 = userService.getById(id); // 第1次访问
|
||||
assertEquals(user3.getPassword(), "admin");
|
||||
user.setPassword("123456");
|
||||
userService.updateUser(user);
|
||||
User user4 = userService.getById(id); // 第4次访问
|
||||
assertEquals(user4.getPassword(), "123456");
|
||||
User user4 = userService.getById(id); // 第2次访问
|
||||
assertEquals(user4.getPassword(), "admin");
|
||||
|
||||
// 更新用户密码
|
||||
user4.setPassword("123456");
|
||||
userService.updateUser(user4);
|
||||
|
||||
// 更新完成后再次访问用户
|
||||
User user5 = userService.getById(id); // 第4次访问
|
||||
assertEquals(user5.getPassword(), "123456");
|
||||
|
||||
// 删除用户admin
|
||||
userService.deleteById(id);
|
||||
assertNull(userService.getById(id));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user