spring boot 整合 redis,使用@Cacheable,@CacheEvict,@CachePut,jedisPool操作redis資料庫
好久沒寫文章了,最近換了個公司,入職差不多一個半月了,接觸了不少沒玩過的新東西,這裡放個
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捕獲