首页 后台正文

Spring Boot 入门详解教程之基础篇(四)

yuange 后台 2019-03-10 754 0 Spring Boot

一、前言

当系统的访问量增大时,相应的数据库的性能就逐渐下降。但是,大多数请求都是在重复的获取相同的数据,如果使用缓存,将结果数据放入其中可以很大程度上减轻数据库的负担,提升系统的响应速度。

本篇将介绍 Spring Boot 中缓存和 NoSQL 的使用。上篇文章《Spring Boot 入门之持久层篇(三)》

二、整合缓存

Spring Boot 针对不同的缓存技术实现了不同的封装,本篇主要介绍 EhCache 和 Redis 缓存。

Spring Boot 提供了以下几个注解实现声明式缓存:

注解说明
@EnableCaching开启缓存功能,放在配置类或启动类上
@CacheConfig缓存配置,设置缓存名称
@Cacheable执行方法前先查询缓存是否有数据。有则直接返回缓存数据;否则查询数据再将数据放入缓存
@CachePut执行新增或更新方法后,将数据放入缓存中
@CacheEvict清除缓存
@Caching将多个缓存操作重新组合到一个方法中

2.1 EhCache 缓存

2.1.1 添加依赖


  1. <dependency>

  2. <groupId>org.springframework.boot</groupId>

  3. <artifactId>spring-boot-starter-cache</artifactId>

  4. </dependency>


  5. <dependency>

  6. <groupId>net.sf.ehcache</groupId>

  7. <artifactId>ehcache</artifactId>

  8. </dependency>

2.1.2 添加配置

1)在 src/main/resources 目录下创建 ehcache.xml 文件,内容如下:


  1. <?xml version="1.0" encoding="UTF-8"?>

  2. <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  3. xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">


  4. <!-- 磁盘缓存位置 -->

  5. <diskStore path="java.io.tmpdir/ehcache"/>


  6. <!-- 默认缓存 -->

  7. <defaultCache

  8. maxEntriesLocalHeap="10000"

  9. eternal="false"

  10. timeToIdleSeconds="120"

  11. timeToLiveSeconds="120"

  12. maxEntriesLocalDisk="10000000"

  13. diskExpiryThreadIntervalSeconds="120"

  14. memoryStoreEvictionPolicy="LRU">

  15. <persistence strategy="localTempSwap"/>

  16. </defaultCache>


  17. <!-- 自定义缓存 -->

  18. <cache name="department"

  19. maxElementsInMemory="1000"

  20. eternal="false"

  21. timeToIdleSeconds="50"

  22. timeToLiveSeconds="50"

  23. overflowToDisk="false"

  24. memoryStoreEvictionPolicy="LRU"/>

  25. </ehcache>

说明:


  1. name:Cache 的唯一标识

  2. maxElementsInMemory:内存中允许存储的最大的元素个数

  3. maxElementsOnDisk:硬盘最大缓存个数,0代表无限个

  4. clearOnFlush:内存数量最大时是否清除

  5. eternal:缓存对象是否永久有效,如果是,超时设置将被忽略

  6. overflowToDisk:内存不足(超过 maxElementsInMemory)时,是否启用磁盘缓存

  7. timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大

  8. timeToLiveSeconds:缓存数据的生存时间(TTL),也就是一个元素从构建到消亡的最大时间间隔值,这只能在元素不是永久驻留时有效,如果该值是0就意味着元素可以停顿无穷长的时间

  9. diskPersistent:是否将缓存数据持久化到磁盘上,如果为 true,JVM 重启数据依然存在。默认值是false

  10. diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区

  11. diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒

  12. memoryStoreEvictionPolicy:当达到 maxElementsInMemory 限制时,Ehcache 将根据指定策略清除内存。默认为 LRU(最近最少使用),其他策略有 FIFO(先进先出),LFU(较少使用)

2)application.properties :


  1. # 缓存类型(ehcache、redis)

  2. spring.cache.type=ehcache


  3. # ehcache 配置文件

  4. spring.cache.ehcache.config=classpath:ehcache.xml


  5. # 打印日志,查看 sql

  6. logging.level.com.light.springboot=DEBUG

2.1.3 编码

在持久层篇的基础上,结合 Mybatis 测试:

Service 层:


  1. @CacheConfig(cacheNames = "department")

  2. @Service

  3. public class DepartmentService {


  4. @Autowired

  5. private DepartmentMapper departmentMapper;


  6. @CachePut(key = "#department.id")

  7. public Department save(Department department) {

  8. System.out.println("保存 id=" + department.getId() + " 的数据");

  9. this.departmentMapper.insert(department);

  10. return department;

  11. }


  12. @CachePut(key = "#department.id")

  13. public Department update(Department department) {

  14. System.out.println("修改 id=" + department.getId() + " 的数据");

  15. this.departmentMapper.update(department);

  16. return department;

  17. }


  18. @Cacheable(key = "#id")

  19. public Department getDepartmentById(Integer id) {

  20. System.out.println("获取 id=" + id + " 的数据");

  21. Department department = this.departmentMapper.getById(id);

  22. return department;

  23. }


  24. @CacheEvict(key = "#id")

  25. public void delete(Integer id) {

  26. System.out.println("删除 id=" + id + " 的数据");

  27. this.departmentMapper.deleteById(id);

  28. }

  29. }

控制层:


  1. @Controller

  2. @RequestMapping("department")

  3. @ResponseBody

  4. public class DepartmentController {


  5. @Autowired

  6. private DepartmentService departmentService;


  7. @RequestMapping("save")

  8. public Map<String,Object> save(Department department) {

  9. this.departmentService.save(department);


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

  11. map.put("code", "200");

  12. map.put("msg", "保存成功");

  13. return map;

  14. }


  15. @RequestMapping("get/{id}")

  16. public Map<String,Object> get(@PathVariable("id") Integer id) {

  17. Department department = this.departmentService.getDepartmentById(id);


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

  19. map.put("code", "200");

  20. map.put("msg", "获取成功");

  21. map.put("data", department);

  22. return map;

  23. }


  24. @RequestMapping("update")

  25. public Map<String,Object> update(Department department) {

  26. this.departmentService.update(department);


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

  28. map.put("code", "200");

  29. map.put("msg", "修改成功");

  30. return map;

  31. }


  32. @RequestMapping("delete/{id}")

  33. public Map<String,Object> delete(@PathVariable("id") Integer id) {

  34. this.departmentService.delete(id);


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

  36. map.put("code", "200");

  37. map.put("msg", "删除成功");

  38. return map;

  39. }

  40. }

启动类:

添加 @EnableCaching 注解,开启缓存功能。


  1. @EnableCaching

  2. @SpringBootApplication

  3. public class SpringbootNosqlApplication {


  4. public static void main(String[] args) {

  5. SpringApplication.run(SpringbootNosqlApplication.class, args);

  6. }

  7. }


2.1.4 测试说明

1) 发起保存请求:


  1. 保存 id=2 的数据

  2. 2017-12-06 14:50:48.800 DEBUG 680 --- [nio-8081-exec-7] c.l.s.dao.DepartmentMapper.insert : ==> Preparing: insert into department(id,name,descr) values(?,?,?)

  3. 2017-12-06 14:50:48.801 DEBUG 680 --- [nio-8081-exec-7] c.l.s.dao.DepartmentMapper.insert : ==> Parameters: 2(Integer), Ehcache 部门(String), Ehcache(String)

  4. 2017-12-06 14:50:48.868 DEBUG 680 --- [nio-8081-exec-7] c.l.s.dao.DepartmentMapper.insert : <== Updates: 1

2) 保存成功后,立刻发起查询请求,没有日志打印,但返回对象数据,说明数据是从缓存中获取。

3) 发起修改请求:


  1. 修改 id=2 的数据

  2. 2017-12-06 14:51:16.588 DEBUG 680 --- [nio-8081-exec-8] c.l.s.dao.DepartmentMapper.update : ==> Preparing: update department set name = ? , descr = ? where id = ?

  3. 2017-12-06 14:51:16.589 DEBUG 680 --- [nio-8081-exec-8] c.l.s.dao.DepartmentMapper.update : ==> Parameters: Ehcache 部门2(String), Ehcache2(String), 2(Integer)

  4. 2017-12-06 14:51:16.657 DEBUG 680 --- [nio-8081-exec-8] c.l.s.dao.DepartmentMapper.update : <== Updates: 1

4) 修改成功后,立刻发起查询请求,没有日志打印,但返回修改后的对象数据,说明缓存中的数据已经同步。

5) 发起删除请求:


  1. 删除 id=2 的数据

  2. 2017-12-06 14:52:07.572 DEBUG 680 --- [nio-8081-exec-1] c.l.s.dao.DepartmentMapper.deleteById : ==> Preparing: delete from department where id = ?

  3. 2017-12-06 14:52:07.572 DEBUG 680 --- [nio-8081-exec-1] c.l.s.dao.DepartmentMapper.deleteById : ==> Parameters: 2(Integer)

  4. 2017-12-06 14:52:07.613 DEBUG 680 --- [nio-8081-exec-1] c.l.s.dao.DepartmentMapper.deleteById : <== Updates: 1

6) 删除成功后,立刻发起查询请求,控制台打印 sql 语句,说明缓存数据被删除,需要查询数据库。


  1. 获取 id=2 的数据

  2. 2017-12-06 14:52:40.324 DEBUG 680 --- [nio-8081-exec-3] c.l.s.dao.DepartmentMapper.getById : ==> Preparing: select id,name,descr from department where id = ?

  3. 2017-12-06 14:52:40.325 DEBUG 680 --- [nio-8081-exec-3] c.l.s.dao.DepartmentMapper.getById : ==> Parameters: 2(Integer)

  4. 2017-12-06 14:52:40.328 DEBUG 680 --- [nio-8081-exec-3] c.l.s.dao.DepartmentMapper.getById : <== Total: 0

2.2 Redis 缓存

2.2.1 添加依赖


  1. <dependency>

  2. <groupId>org.springframework.boot</groupId>

  3. <artifactId>spring-boot-starter-data-redis</artifactId>

  4. </dependency>

2.2.2 添加配置

application.properties :


  1. # redis 配置

  2. spring.redis.host=192.168.2.11

  3. spring.redis.port=6379

  4. spring.redis.password=redis123

  5. # 缓存过期时间,单位毫秒

  6. spring.cache.redis.time-to-live=60000


  7. # 缓存类型(ehcache、redis)

  8. spring.cache.type=redis


  9. # 打印日志,查看 sql

  10. logging.level.com.light.springboot=DEBUG

注意:spring.cache.type=redis,缓存类型设置成 redis。

完成上边 2 个步骤后,其他步骤与测试 Ehcache 时的步骤一致。

测试结果也一致,此处省略。

三、整合 Redis

上一个小节其实已经介绍了 Spring Boot 整合 Redis 的内容。

在添加 redis 依赖包启动项目后,Spring Boot 会自动配置 RedisCacheManger 和 RedisTemplate 的 Bean。如果开发者不想使用 Spring Boot 写好的 Redis 缓存,而是想使用其 API 自己实现缓存功能、消息队列或分布式锁之类的需求时,可以继续往下浏览。

Spring Data Redis 为我们提供 RedisTemplate 和 StringRedisTemplate 两个模板进行数据操作,它们主要 的访问方法如下:

方法说明
opsForValue()操作简单属性的数据
opsForList()操作含有 list 的数据
opsForSet()操作含有 set 的数据
opsForZSet()操作含有 zset 的数据
opsForHash()操作含有 hash 的数据

3.1 添加依赖


  1. <dependency>

  2. <groupId>org.springframework.boot</groupId>

  3. <artifactId>spring-boot-starter-data-redis</artifactId>

  4. </dependency>

3.2 配置连接


  1. spring.redis.host=192.168.2.11

  2. spring.redis.port=6379

  3. spring.redis.password=redis123

3.3 编码


  1. @Component

  2. public class RedisDao {


  3. @Autowired

  4. private StringRedisTemplate stringRedisTemplate;


  5. public void set(String key, String value) {

  6. this.stringRedisTemplate.opsForValue().set(key, value);

  7. }


  8. public String get(String key) {

  9. return this.stringRedisTemplate.opsForValue().get(key);

  10. }


  11. public void delete(String key) {

  12. this.stringRedisTemplate.delete(key);

  13. }

  14. }

3.4 测试


  1. @RunWith(SpringRunner.class)

  2. @SpringBootTest

  3. public class RedisDaoTest {


  4. @Autowired

  5. private RedisDao redisDao;


  6. @Test

  7. public void testSet() {

  8. String key = "name";

  9. String value = "zhangsan";


  10. this.redisDao.set(key, value);

  11. }


  12. @Test

  13. public void testGet() {

  14. String key = "name";

  15. String value = this.redisDao.get(key);

  16. System.out.println(value);

  17. }


  18. @Test

  19. public void testDelete() {

  20. String key = "name";

  21. this.redisDao.delete(key);

  22. }

  23. }


测试结果省略...

四、整合 MongoDB

Spring Data MongoDB 提供了 MongoTemplate 模板 和 Repository 让开发者进行数据访问。

4.1 添加依赖


  1. <dependency>

  2. <groupId>org.springframework.boot</groupId>

  3. <artifactId>spring-boot-starter-data-mongodb</artifactId>

  4. </dependency>

4.2 配置连接


  1. spring.data.mongodb.host=192.168.2.31

  2. spring.data.mongodb.port=27017

  3. spring.data.mongodb.database=test

4.3 编码

4.3.1 使用 MongoTemplate


  1. @Component

  2. public class MongodbDao {


  3. @Autowired

  4. private MongoTemplate mongoTemplate;


  5. public void insert(Department department) {

  6. this.mongoTemplate.insert(department);

  7. }


  8. public void deleteById(int id) {

  9. Criteria criteria = Criteria.where("id").is(id);

  10. Query query = new Query(criteria);

  11. this.mongoTemplate.remove(query, Department.class);

  12. }


  13. public void update(Department department) {

  14. Criteria criteria = Criteria.where("id").is(department.getId());

  15. Query query = new Query(criteria);

  16. Update update = new Update();

  17. update.set("descr", department.getDescr());

  18. this.mongoTemplate.updateMulti(query, update, Department.class);

  19. }


  20. public Department getById(int id) {

  21. Criteria criteria = Criteria.where("id").is(id);

  22. Query query = new Query(criteria);

  23. return this.mongoTemplate.findOne(query, Department.class);

  24. }


  25. public List<Department> getAll() {

  26. List<Department> userList = this.mongoTemplate.findAll(Department.class);

  27. return userList;

  28. }


  29. }

4.3.2 使用 Repository


  1. public interface DepartmentRepository extends MongoRepository<Department, Integer> {



  2. }

测试方式与 Redis 测试大同小异,测试结果省略...

五、源码下载


评论

在线客服-可直接交谈

您好!有什么需要可以为您服务吗?