好久没写文章了,最近换了个公司,入职差不多一个半月了,接触了不少没玩过的新东西,这里放个
spring boot 整合 redis的demo吧。
先看一下demo目录:
如何创建spring boot项目我就不说了很简单,不会百度一大把。
先看一下pom需要哪些包:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
<version>1.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.29</version>
</dependency>
</dependencies>
这些包都很见名知意我就不说每个干嘛用的了。
先看一下配置文件吧,主要就3个东西,redis,mysql,jpa:
#redis相关配置
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=6000
#mysql相关配置
#mysql服务器地址
spring.datasource.url =jdbc:mysql://localhost:3306/redis_test
#mysql服务器连接用户名
spring.datasource.username = root
#mysql服务器连接密码
spring.datasource.password = root
#mysql服务器连接驱动
spring.datasource.driverClassName =com.mysql.jdbc.Driver
# 连接池最大连接数
spring.datasource.max-active=20
# 连接池中的最大空闲连接
spring.datasource.max-idle=8
# 连接池中的最小空闲连接
spring.datasource.min-idle=8
spring.datasource.initial-size=10
# Specify the DBMS
spring.jpa.database = MYSQL
# Show or not log for each sqlquery
spring.jpa.show-sql = true
# Hibernate ddl auto (create,create-drop, update)
spring.jpa.hibernate.ddl-auto = update
# Naming strategy
spring.jpa.hibernate.naming-strategy =org.hibernate.cfg.ImprovedNamingStrategy
# stripped before adding them tothe entity manager)
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
既然用到redis,需要先写一个RedisUtils类来继承CachingConfigurerSupport,需要我们手动实现一些方法:
@Configuration
@EnableCaching //启用缓存,这个注解很重要;
public class RedisUtils extends CachingConfigurerSupport {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.timeout}")
private int timeout;
@Value("${spring.redis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.pool.max-wait}")
private long maxWaitMillis;
// @Value("${spring.redis.password}")
// private String password;
@Bean
public JedisPool redisPoolFactory() {
System.out.println("JedisPool注入成功!!");
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
//本地redis未设置密码,所以第五个参数password不传
JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout);
return jedisPool;
}
/**
* 缓存管理器.
* @param redisTemplate
* @return
*/
@Bean
public CacheManager cacheManager(RedisTemplate<?,?> redisTemplate) {
CacheManager cacheManager = new RedisCacheManager(redisTemplate);
return cacheManager;
}
/**
* redis模板操作类,类似于jdbcTemplate的一个类;
* 虽然CacheManager也能获取到Cache对象,但是操作起来没有那么灵活;
* 这里在扩展下:RedisTemplate这个类不见得很好操作,我们可以在进行扩展一个我们
* 自己的缓存类,比如:RedisStorage类;
* @param redisConnectionFactory : 通过Spring进行注入,参数在application.properties进行配置;
* @return
*/
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate(redisConnectionFactory);
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.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
/**
* 自定义key生成策略
* 类名+方法名+参数(适用于分布式缓存),默认key生成策略分布式下有可能重复被覆盖
* @return
*/
@Bean
public KeyGenerator keyGenerator() {
return (o, method, objects) -> {
StringBuilder sb = new StringBuilder();
sb.append(o.getClass().getName());
sb.append("." + method.getName() + "(");
for (Object obj : objects) {
sb.append(obj.toString());
}
sb.append(")");
return sb.toString();
};
}
}
看一下controller,方法都见名知意我就不写注释了,这里介绍一下controller用到的3个注解作用:
@Cacheable:主要用作查询,如果根据key从redis中没查到就去mysql查并且把返回结果插入redis,下次直接从redis取;
@CachePut:主要用作更新,如果根据key从redis中没查到就去mysql查并且把返回结果插入redis,如果从redis查到那么也去mysql查一遍,所以不管redis中有没有都去查mysql,所以主要用作更新
@CacheEvict:主要用作删除,根据key从redis中删除数据
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/findById/{id}")
// @Cacheable(value = "user",keyGenerator = "keyGenerator")
@Cacheable(value = "zh",key = "'user_' + #id")
public User findById(@PathVariable Integer id) {
System.err.println("UserController.findById()=========从数据库中进行获取的....id = " + id);
return userService.findById(id);
}
@GetMapping("/deleteById/{id}")
@CacheEvict(value = "zh",key = "'user_' + #id")
public void deleteById(@PathVariable Integer id){
System.out.println("UserController.deleteById().从数据库中删除.");
userService.deleteById(id);
}
@PostMapping("/save")
@CachePut(value = "zh",key = "'user_' + #user.id")
public User save(User user){
return userService.save(user);
}
@PostMapping("/updateNameById")
public void updateNameById(User user){
userService.updateNameById(user);
}
}
看下service和serviceImpl,前三个方法是加了注解操作redis,第四个方法是使用jedisPool操作数据库:
public interface UserService {
User findById(Integer id);
void deleteById(Integer id);
User save(User user);
void updateNameById(User user);
}
@Service
public class UserServicrImpl implements UserService {
@Autowired
private RedisTemplate<String,String> redisTemplate;
@Autowired
private JedisPool jedisPool;
@Autowired
private UserDao userDao;
@Override
public User findById(Integer id) {
return userDao.findOne(id);
}
@Override
public void deleteById(Integer id) {
userDao.delete(id);
}
@Override
public User save(User user) {
return userDao.save(user);
}
@Override
public void updateNameById(User user) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("连接不上redis");
}
JSONObject jsonUser= (JSONObject) JSONObject.toJSON(user);
jedis.set("user_" + user.getId(),jsonUser.toJSONString());
jedis.close();
}
}
dao继承一下jpa的类就行了,提供了基本的增删改查,User实体类我就不贴了:
public interface UserDao extends CrudRepository<User, Integer> {
}
总结一下:我在写demo的时候思考为什么注解很方便的操作redis,还要用jedisPool操作数据库呢?
其实原因很简单,因为实际业务逻辑会有很复杂的情况,注解只适用与简单的操作。因为jedisPool连接池可能连不上redis所以要加try/catch捕获