Spring Boot中的快取支援——使用Redis做集中式快取實戰
阿新 • • 發佈:2018-12-19
一 點睛
雖然EhCache已經能夠適用很多應用場景,但是由於EhCache是程序內的快取框架,在叢集模式下時,各應用伺服器之間的快取都是獨立的,因此在不同伺服器的程序間會存在快取不一致的情況。即使EhCache提供了叢集環境下的快取同步策略,但是同步依然需要一定的時間,短暫的快取不一致依然存在。
在一些要求高一致性(任何資料變化都能及時的被查詢到)的系統和應用中,就不能再使用EhCache來解決了,這個時候使用集中式快取是個不錯的選擇,因此本篇將介紹如何在Spring Boot的快取支援中使用Redis進行資料快取。
二 實戰
1 新增依賴
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.21</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> </dependency> </dependencies>
2 實體類
package com.didispace.domain; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import java.io.Serializable; /** * @author 程式猿DD * @version 1.0.0 * @date 16/3/21 下午3:35. * @blog http://blog.didispace.com */ @Entity public class User implements Serializable { @Id @GeneratedValue private Long id; @Column(nullable = false) private String name; @Column(nullable = false) private Integer age; public User(){} public User(String name, Integer age) { this.name = name; this.age = age; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
3 資料訪問
package com.didispace.domain; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.data.jpa.repository.JpaRepository; @CacheConfig(cacheNames = "users") public interface UserRepository extends JpaRepository<User, Long> { @Cacheable(key = "#p0") User findByName(String name); @CachePut(key = "#p0.name") User save(User user); }
4 啟動類
package com.didispace;
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);
}
}
5 application.properties配置
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop
spring.jpa.properties.hibernate.show_sql=true
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
6 測試類
package com.didispace;
import com.didispace.domain.User;
import com.didispace.domain.UserRepository;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.cache.CacheManager;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class ApplicationTests {
@Autowired
private UserRepository userRepository;
@Autowired
private CacheManager cacheManager;
@Before
public void before() {
userRepository.save(new User("AAA", 10));
}
@Test
public void test() throws Exception {
User u1 = userRepository.findByName("AAA");
System.out.println("第一次查詢:" + u1.getAge());
User u2 = userRepository.findByName("AAA");
System.out.println("第二次查詢:" + u2.getAge());
u1.setAge(20);
userRepository.save(u1);
User u3 = userRepository.findByName("AAA");
System.out.println("第三次查詢:" + u3.getAge());
}
}
三 測試結果
Hibernate: insert into user (age, name) values (?, ?)
第一次查詢:10
第二次查詢:10
Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?
Hibernate: update user set age=?, name=? where id=?
第三次查詢:20
可以看到,我們的第三次查詢獲得了正確的結果!同時,我們的第一次查詢也不是通過select查詢獲得的,因為在初始化資料的時候,呼叫save方法時,就已經將這條資料加入了redis快取中,因此後續的查詢就直接從redis中獲取了。