Spring Boot 入门之缓存和 NoSQL 篇(四)

一、前言

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

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

二、整合缓存

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

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

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

2.1 EhCache 缓存

2.1.1 添加依赖
 
    
1
2
3
4
5
6
7
8
9
 
    
<dependency>
<groupId>org.springframework.boot </groupId>
<artifactId>spring-boot-starter-cache </artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache </groupId>
<artifactId>ehcache </artifactId>
</dependency>
2.1.2 添加配置

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

 
    
1
2
3
4
5
6
7
8
 
    
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd">
<cache name="department"
eternal="false"
maxEntriesLocalHeap="0"
timeToIdleSeconds="50">
</cache>
</ehcache>

application.properties :

 
    
1
2
3
4
5
 
    
spring.cache.type=ehcache
spring.cache.ehcache.config=classpath:ehcache.xml
# 打印日志,查看 sql
logging.level.com.light.springboot=DEBUG
2.1.3 编码

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

Service 层:

 
    
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
27
28
29
30
31
32
33
34
 
    
@CacheConfig(cacheNames = "department")
@Service
public class DepartmentService {
@Autowired
private DepartmentMapper departmentMapper;
@CachePut(key = "#department.id")
public Department save(Department department) {
System.out.println( "保存 id=" + department.getId() + " 的数据");
this.departmentMapper.insert(department);
return department;
}
@CachePut(key = "#department.id")
public Department update(Department department) {
System.out.println( "修改 id=" + department.getId() + " 的数据");
this.departmentMapper.update(department);
return department;
}
@Cacheable(key = "#id")
public Department getDepartmentById(Integer id) {
System.out.println( "获取 id=" + id + " 的数据");
Department department = this.departmentMapper.getById(id);
return department;
}
@CacheEvict(key = "#id")
public void delete(Integer id) {
System.out.println( "删除 id=" + id + " 的数据");
this.departmentMapper.deleteById(id);
}
}

控制层:

 
    
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
 
    
@Controller
@RequestMapping( "department")
@ResponseBody
public class DepartmentController {
@Autowired
private DepartmentService departmentService;
@RequestMapping( "save")
public Map<String,Object> save(Department department) {
this.departmentService.save(department);
Map<String,Object> map = new HashMap<String,Object>();
map.put( "code", "200");
map.put( "msg", "保存成功");
return map;
}
@RequestMapping( "get/{id}")
public Map<String,Object> get(@PathVariable("id") Integer id) {
Department department = this.departmentService.getDepartmentById(id);
Map<String,Object> map = new HashMap<String,Object>();
map.put( "code", "200");
map.put( "msg", "获取成功");
map.put( "data", department);
return map;
}
@RequestMapping( "update")
public Map<String,Object> update(Department department) {
this.departmentService.update(department);
Map<String,Object> map = new HashMap<String,Object>();
map.put( "code", "200");
map.put( "msg", "修改成功");
return map;
}
@RequestMapping( "delete/{id}")
public Map<String,Object> delete(@PathVariable("id") Integer id) {
this.departmentService.delete(id);
Map<String,Object> map = new HashMap<String,Object>();
map.put( "code", "200");
map.put( "msg", "删除成功");
return map;
}
}

启动类:

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

 
    
1
2
3
4
5
6
7
8
 
    
@EnableCaching
@SpringBootApplication
public class SpringbootNosqlApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootNosqlApplication.class, args);
}
}
2.1.4 测试说明

1) 发起保存请求:

 
    
1
2
3
4
 
    
保存 id=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(?,?,?)
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)
2017-12-06 14:50:48.868 DEBUG 680 --- [nio-8081-exec-7] c.l.s.dao.DepartmentMapper.insert : <== Updates: 1

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

3) 发起修改请求:

 
    
1
2
3
4
 
    
修改 id=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 = ?
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)
2017-12-06 14:51:16.657 DEBUG 680 --- [nio-8081-exec-8] c.l.s.dao.DepartmentMapper.update : <== Updates: 1

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

5) 发起删除请求:

 
    
1
2
3
4
 
    
删除 id=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 = ?
2017-12-06 14:52:07.572 DEBUG 680 --- [nio-8081-exec-1] c.l.s.dao.DepartmentMapper.deleteById : ==> Parameters: 2(Integer)
2017-12-06 14:52:07.613 DEBUG 680 --- [nio-8081-exec-1] c.l.s.dao.DepartmentMapper.deleteById : <== Updates: 1

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

 
    
1
2
3
4
 
    
获取 id=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 = ?
2017-12-06 14:52:40.325 DEBUG 680 --- [nio-8081-exec-3] c.l.s.dao.DepartmentMapper.getById : ==> Parameters: 2(Integer)
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
2
3
4
 
    
<dependency>
<groupId>org.springframework.boot </groupId>
<artifactId>spring-boot-starter-data-redis </artifactId>
</dependency>
2.2.2 添加配置

application.properties :

 
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
    
spring.redis.host=192.168.2.11
spring.redis.port=6379
spring.redis.password=
spring.redis.database=0
spring.redis.pool.max-active=8
spring.redis.pool.max-idle=8
spring.redis.pool.max-wait=-1
spring.redis.pool.min-idle=0
spring.redis.timeout=0
spring.cache.type=redis
# 打印日志,查看 sql
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
2
3
4
 
    
<dependency>
<groupId>org.springframework.boot </groupId>
<artifactId>spring-boot-starter-data-redis </artifactId>
</dependency>

3.2 配置连接

 
    
1
2
3
4
5
6
7
8
9
 
    
spring.redis.host=192.168.2.11
spring.redis.port=6379
spring.redis.password=
spring.redis.database=0
spring.redis.pool.max-active=8
spring.redis.pool.max-idle=8
spring.redis.pool.max-wait=-1
spring.redis.pool.min-idle=0
spring.redis.timeout=0

3.3 编码

 
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
    
@Component
public class RedisDao {
@Autowired
private StringRedisTemplate stringRedisTemplate;
public void set(String key, String value) {
this.stringRedisTemplate.opsForValue().set(key, value);
}
public String get(String key) {
return this.stringRedisTemplate.opsForValue().get(key);
}
public void delete(String key) {
this.stringRedisTemplate.delete(key);
}
}

3.4 测试

 
    
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
27
28
 
    
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisDaoTest {
@Autowired
private RedisDao redisDao;
@Test
public void testSet() {
String key = "name";
String value = "zhangsan";
this.redisDao.set(key, value);
}
@Test
public void testGet() {
String key = "name";
String value = this.redisDao.get(key);
System.out.println(value);
}
@Test
public void testDelete() {
String key = "name";
this.redisDao.delete(key);
}
}

测试结果省略…

四、整合 MongoDB

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

4.1 添加依赖

 
    
1
2
3
4
 
    
<dependency>
<groupId>org.springframework.boot </groupId>
<artifactId>spring-boot-starter-data-mongodb </artifactId>
</dependency>

4.2 配置连接

 
    
1
2
3
 
    
spring.data.mongodb.host=192.168.2.25
spring.data.mongodb.port=27017
spring.data.mongodb.database=test

4.3 编码

4.3.1 使用 MongoTemplate
 
    
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
27
28
29
30
31
32
33
34
35
36
 
    
@Component
public class MongodbDao {
@Autowired
private MongoTemplate mongoTemplate;
public void insert(User user) {
this.mongoTemplate.insert(user);
}
public void deleteById(int id) {
Criteria criteria = Criteria.where( "id").is(id);
Query query = new Query(criteria);
this.mongoTemplate.remove(query, User.class);
}
public void update(User User) {
Criteria criteria = Criteria.where( "id").is(User.getId());
Query query = new Query(criteria);
Update update = new Update();
update.set( "password", User.getPassword());
this.mongoTemplate.updateMulti(query, update, User.class);
}
public User getById(int id) {
Criteria criteria = Criteria.where( "id").is(id);
Query query = new Query(criteria);
return this.mongoTemplate.findOne(query, User.class);
}
public List<User> getAll() {
List<User> userList = this.mongoTemplate.findAll(User.class);
return userList;
}
}
4.3.2 使用 Repository
 
    
1
2
3
4
 
    
public interface UserRepository extends MongoRepository<User, Integer> {
}

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

五、参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值