天天看點

Spring之路(47)–Spring程式設計式緩存管理執行個體

1. 程式設計式緩存管理

還記得之前講過的程式設計式事務管理與聲明式事務管理嗎,程式設計式管理說白了就是自己手工程式設計去管理。

因為手工程式設計式的管理方式,更加基礎,更加容易了解,是以我們從程式設計式緩存管理說起。

2. 實作方式

其實思路非常簡單,緩存是針對方法的,我們将對方法的請求加入緩存中,如果再次對該方法發起同樣請求(同一方法且參數相同),則不執行該方法,直接取出緩存即可。

3. 項目準備

為了可以使用AOP,再進行本文内容時,除了前面一直提到Spring的jar包,還需要引入aspectjweaver-1.8.1.jar,這個包是Spring AOP所需要的。

4. 不使用緩存的情況

4.1 定義資料DO、資料通路DAO、資料服務Service

首先定義BlogDao用來通路資料庫,根據部落格表的id擷取部落格資訊

@Repository // 注冊為bean

public class BlogDao {

@Autowired // 自動注入

private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

/**

 * 查詢資料庫

 */

public BlogDo getById(Long id) {

 System.out.println("執行getById:" + id);

 Map<String, Object> map = new HashMap<>();

 map.put("id", id);

 return namedParameterJdbcTemplate.queryForObject("select * from blog where id=:id", map,

   new RowMapper<BlogDo>() {

    @Override

    public BlogDo mapRow(ResultSet rs, int rowNum) throws SQLException {

     BlogDo blog = new BlogDo();

     blog.setAuthor(rs.getString("author"));

     blog.setContent(rs.getString("content"));

     blog.setId(rs.getLong("id"));

     blog.setTitle(rs.getString("title"));

     return blog;

    }

   });

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

然後定義BlogService提供操作封裝。

@Service//注冊bean

public class BlogService {

@Autowired//自動注入

private BlogDao blogDao;

 return blogDao.getById(id);

資料對象BlogDo就不用多說了:

public class BlogDo {

private Long id;

private String title;

private String author;

private String content;

//省略get set

4.2 編寫Spring配置類SpringConfig

在配置類中開啟bean掃描,以便将BlogService和BlogDao注冊bean,同時注冊資料源bean和namedParameterJdbcTemplate用于操作資料庫。

@Configuration // 配置類

@ComponentScan(basePackages = { "org.maoge.cachedemo.mannual" }) // 掃描包以便發現注解配置的bean

public class SpringConfig {

// 配置資料源

@Bean

public DataSource dataSource() {

 DruidDataSource dataSource = new DruidDataSource();

 dataSource.setDriverClassName("com.mysql.jdbc.Driver");

 dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/myblog?useUnicode=true&characterEncoding=utf-8");

 dataSource.setUsername("root");

 dataSource.setPassword("Easy@0122");

 return dataSource;

// 配置namedParameterJdbcTemplate元件

public NamedParameterJdbcTemplate namedParameterJdbcTemplate() {

 NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(dataSource());// 注入dataSource

 return template;

4.3 測試

從容器中取出BlogService,然後調用其getList方法進行測試:

public class Main {

public static void main(String[] args) throws SQLException {

 // 擷取容器

 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);

 // 擷取blogService元件

 BlogService blogService = context.getBean("blogService", BlogService.class);

 // 測試擷取清單

 for(int i=0;i<10;i++) {

  blogService.getById(1L);

 }

輸出結果如下,可見真實的調用了BlogDao的getById方法10次。

執行getById:1

5. 程式設計式管理管理的情況

5.1 修改配置類啟用緩存并注冊緩存管理器

首先通過@EnableCaching 啟用緩存功能。然後注冊緩存管理器bean,我們通過緩存管理器對緩存進行管理。

@EnableCaching // 啟用緩存

// 配置緩存管理器

public CacheManager cacheManager() {

 SimpleCacheManager cacheManager = new SimpleCacheManager();

 //緩存管理器中有很多緩存caches,其中一個名字為blogs

 cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("blogs")));

 return cacheManager;

27

28

29

務必注意,我們像緩存管理其中添加了一個名字為blogs的ConcurrentMapCache類型對象,該對象是個字典形式的緩存,也就是說在blogs這個緩存,參數隻要确定了,其緩存的值就确定了。

5.2 調用BlogService.getById時添加緩存邏輯

不存在緩存時,将結果放入緩存;存在緩存,則不再執行具體方法,直接傳回緩存。

@Autowired//自歐東注入

private CacheManager cacheManager;

 //取出名字為blogs的緩存

 Cache cache=cacheManager.getCache("blogs");

 //判斷針對參數id的值,是否有緩存存在

 if(cache.get(id)==null) {//不存在,則查詢資料庫,并将結果納入緩存

  BlogDo result=blogDao.getById(id);

  cache.put(id, result);

  return result;

 }else {//存在則直接傳回緩存即可

  return (BlogDo)cache.get(id).get();//這個取值方式稍微有點繞

看明白了嗎,首先緩存管理器可能要管理很多個緩存,比如使用者緩存、角色緩存、機構資訊緩存等等,是以需要先定義有幾個緩存Cache,此處隻有一個就是cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("blogs")));。

然後,一個緩存其實就是一個線程安全的鍵值對,将方法的參數作為鍵,方法的傳回值作為值,存儲起來。當新的請求到達時,如果請求參數都相同,則不必再去查資料庫了,直接傳回緩存就行,反正請求的是一個東西。

5.3 測試

同樣代碼進行測試

結果輸出如下:

這意味着什麼,我們成功的使用了緩存,對資料庫的通路得到了極大的減少。如果使用得當的話,系統性能會得到一個躍進!

如果你不放心的話,可以下個斷點,看看是不是傳回的值是正确的。

上面的緩存方式太複雜了,你應該看到了模闆代碼的痕迹,凡是重複必能抽象優化,這種模闆代碼用AOP解決,SOEASY啊。

然後緩存其實還有不少注意點,我将在接下來給大家詳細示範和解釋。