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