文章目录
springboot结合spring Cache + redis缓存数据
项目中简单使用
//根据id查询子节点数据列表
@Override
@Cacheable(value = "dict", keyGenerator = "keyGenerator")
public List<Dict> findChlidData(Long id) {
QueryWrapper<Dict> wrapper = new QueryWrapper();
wrapper.eq("parent_id", id);
List<Dict> dictslist = dictMapper.selectList(wrapper);
for (Dict dict : dictslist) {
boolean children = this.isChildren(dict.getId());
dict.setHasChildren(children);
}
return dictslist;
}
//---------------------------------------------------------------------------
@Override
@CacheEvict(value = "dict", allEntries = true)
public void importData(MultipartFile file) {
try {
//调用easyExcel导入excel文件,插入到数据库中
EasyExcel.read(file.getInputStream(), DictEeVo.class, new DictListener(dictMapper)).sheet().doRead();
} catch (IOException e) {
e.printStackTrace();
}
}
SpringCache的注解应用:
@Cacheable(value = "dict", keyGenerator = "keyGenerator")
:spring的Redis注解,使用在方法上,表示该方法的返回结果会放到缓存中,以后使用相同的参数调用该方法是,会返回缓存中的值,而不会再去执行方法。
当一个支持缓存的方法在对象内部被调用时不会触发缓存功能
- @Cacheable中value、cacheNames指定缓存名key 二选一,支持一个方法关联多个缓存,当执行方法之前,这些关联的每一个缓存都会被检查,只要其中一个缓存命中,那么缓存中的值会被返回。
- key的生成有两种方式:显式指定和使用keyGenerator自动生成。
- 不指定key时,会根据keyGenerator参数自动生成。spring默认的SimpleKeyCenerator,在spring自动配置中,如果没有参数,返回SimpleKey.EMPTY;如果有一个参数,返回参数实例;多个参数,返回一个包含所有参数的SimpleKey。
- spring 官方更推荐显式指定 key 的方式,即指定 @Cacheable 的 key 参数。可以根据参数来生成指定的key,使用spring的SpEL表达式,如:
@Cacheable(value = {"menuById"}, key = "'id-' + #menu.id")
public Menu findById(Menu menu)
@CacheEvict(value = "dict", allEntries = true)
:@CacheEvict会在方法执行前或执行后移除SpringCache中的某些元素。用来标注需要清除缓存元素的方法或类。
- value:指定缓存名。
- key:表示需要清除的是哪个key, 如果未指定则使用默认策略生成key。
- allEntries:表示是否需要删除缓存中的所有元素,默认为false,设置为true时,Spring Cache将忽略指定的key,清除所有的缓存。
@CachePut:声明支持缓存,于@Cacheable不同的是,@CachePut,在执行方法前不回去检查缓存中是否存在,而是每次都去执行该方法,并将执行结果以键值对的形式存入到缓存中。
Spring Cache 结合 redis 缓存配置:
依赖导入
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
<!-- spring2.X集成redis所需common-pool2-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.6.0</version>
</dependency>
application.properties
#Redis接口配置
spring.redis.host=192.168.1.1
spring.redis.port=6379
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=5000
##最大阻塞等待时间(负数表示没限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0
添加配置文件config
https://blog.csdn.net/weixin_44773752/article/details/120315837
@EnableCaching
:开启缓存,并配置redis的缓存管理器,是一个后置处理器,检查每一个Spring bean 的public方法是否有缓存注解,如果有缓存注解,自动创建一一个代理拦截方法调用和处理响应的缓存行为。
RedisTemplate操作redis
使用spring提供的spring-data-redis,通过简单的配置访问redis服务,对Jedis、Jredis、RJC进行了高度的封装,RedisTemplate提供了redis的各种操作、异常处理序列化、支持订阅发布功能、并对spring-cache进行了实现。
spring-data-redis对redis提供:
-
连接池自动管理,提供了高度封装的RedisTemplate类。
-
针对jedis客户端中大量api进行了归类封装,将同一类操作封装为operation接口。
- ValueOperations:简单K-V操作
- SetOperations:set类型数据操作
- ZSetOperations:zset类型数据操作
- HashOperations:针对map类型的数据操作
- ListOperations:针对list类型的数据操作
-
提供了对key的“bound”(绑定)便捷化操作API,可以通过bound封装指定的key,然后进行一系列的操作而无须“显式”的再次指定Key,即BoundKeyOperations:
- BoundValueOperations
- BoundSetOperations
- BoundListOperations
- BoundSetOperations
- BoundHashOperations
-
将事务操作封装,有容器控制。
-
针对数据的“序列化/反序列化”,提供了多种可选择策略(RedisSerializer)
JdkSerializationRedisSerializer:POJO对象的存取场景,使用JDK本身序列化机制,将pojo类通过ObjectInputStream/ObjectOutputStream进行序列化操作,最终redis-server中将存储字节序列。是目前最常用的序列化策略。
StringRedisSerializer:Key或者value为字符串的场景,根据指定的charset对数据的字节序列编码成string,是“new String(bytes, charset)”和“string.getBytes(charset)”的直接封装。是最轻量级和高效的策略。
JacksonJsonRedisSerializer:jackson-json工具提供了javabean与json之间的转换能力,可以将pojo实例序列化成json格式存储在redis中,也可以将json格式的数据转换成pojo实例。因为jackson工具在序列化和反序列化时,需要明确指定Class类型,因此此策略封装起来稍微复杂。【需要jackson-mapper-asl工具支持】
springboot结合MongoDB
MongoDB主要是为web应用提供可扩展的高性能数据存储解决方案,是一个面向文档存储的数据库。
MongoDB将数据存储为一个文档,数据结构以key-value组成。MongDB文档类似于JSON对象,字段值可以包含其他文档、数组及文档数组。
适用场景
- 网站数据:Mongo非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
- 缓存:由于性能很高,Mongo也适合作为信息基础设施的缓存层。在系统重启之后,由Mongo搭建的持久化缓存层可以避免下层的数据源过载。
- 大尺寸,低价值的数据:使用传统的关系型数据库存储一些数据时可能会比较昂贵, 在此之前,很多时候程序员往往会选择传统的文件进行存储。
- 高伸缩性的场景:Mongo非常适合由数十或数百台服务器组成的数据库。Mongo的路线图中已经包含对Map Reduce弓摩的内置支持。
- 用于对象及 JSON数据的存储:Mongo的BSON数据格式非常适合文档化格式的存储 及查询。
不适用场合
- 高度事务性的系统:例如银行或会计系统。传统的关系型数据库目前还是更适用于需要大量原子性复杂事务的应用程序。
- 传统的商业智能应用:针对特定问题的BI数据库会对产生高度优化的查询方式。对于此类应用,数据仓库可能是更合适的选择。
spring-data-mongodb提供了MongoTemplate与MongoRepository两种方式访问mongodb,MongoRepository操作简单,MongoTemplate操作灵活,我们在项目中可以灵活适用这两种方式操作mongodb,MongoRepository的缺点是不够灵活,MongoTemplate正好可以弥补不足。
RedisTemplate:
常用方法
- mongoTemplate.findAll(User.class): 查询User文档的全部数据
- mongoTemplate.findById(, User.class): 查询User文档id为id的数据
- mongoTemplate.find(query, User.class);: 根据query内的查询条件查询
- mongoTemplate.upsert(query, update, User.class): 修改
- mongoTemplate.remove(query, User.class): 删除
- mongoTemplate.insert(User): 新增
- Query对象
- 1、创建一个query对象(用来封装所有条件对象),再创建一个criteria对象(用来构建条件)
- 2、 精准条件:criteria.and(“key”).is(“条件”)
模糊条件:criteria.and(“key”).regex(“条件”) - 3、封装条件:query.addCriteria(criteria)
- 4、大于(创建新的criteria):Criteria gt = Criteria.where(“key”).gt(“条件”)
小于(创建新的criteria):Criteria lt = Criteria.where(“key”).lt(“条件”) - 5、Query.addCriteria(new Criteria().andOperator(gt,lt));
- 6、一个query中只能有一个andOperator()。其参数也可以是Criteria数组。
- 7、排序 :query.with(new Sort(Sort.Direction.ASC, “age”). and(new Sort(Sort.Direction.DESC, “date”)))
@Autowired
private MongoTemplate mongoTemplate;
//模糊查询
@Test
public void findUsersLikeName() {
String name = "est";
String regex = String.format("%s%s%s", "^.*", name, ".*$");
Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
Query query = new Query(Criteria.where("name").regex(pattern));
List<User> userList = mongoTemplate.find(query, User.class);
System.out.println(userList);
}
//分页查询
@Test
public void findUsersPage() {
String name = "est";
int pageNo = 1;
int pageSize = 10;
Query query = new Query();
String regex = String.format("%s%s%s", "^.*", name, ".*$");
Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
query.addCriteria(Criteria.where("name").regex(pattern));
int totalCount = (int) mongoTemplate.count(query, User.class);
List<User> userList = mongoTemplate.find(query.skip((pageNo - 1) * pageSize).limit(pageSize), User.class);
Map<String, Object> pageMap = new HashMap<>();
pageMap.put("list", userList);
pageMap.put("totalCount",totalCount);
System.out.println(pageMap);
}
//修改
@Test
public void updateUser() {
User user = mongoTemplate.findById("5ffbfa2ac290f356edf9b5aa", User.class);
user.setName("test_1");
user.setAge(25);
user.setEmail("493220990@qq.com");
Query query = new Query(Criteria.where("_id").is(user.getId()));
Update update = new Update();
update.set("name", user.getName());
update.set("age", user.getAge());
update.set("email", user.getEmail());
UpdateResult result = mongoTemplate.upsert(query, update, User.class);
long count = result.getModifiedCount();
System.out.println(count);
}
//删除操作
@Test
public void delete() {
Query query =
new Query(Criteria.where("_id").is("5ffbfa2ac290f356edf9b5aa"));
DeleteResult result = mongoTemplate.remove(query, User.class);
long count = result.getDeletedCount();
System.out.println(count);
}
}
MongoRepository:
Spring Data提供了对mongodb数据访问的支持,我们只需要继承MongoRepository类,按照Spring Data规范就可以了。
SpringData方法定义规范:
1、不是随便声明的,而需要符合一定的规范
2、 查询方法以find | read | get开头
3、 涉及条件查询时,条件的属性用条件关键字连接
4、 要注意的是:条件属性首字母需要大写
5、 支持属性的级联查询,但若当前类有符合条件的属性则优先使用,而不使用级联属性,若需要使用级联属性,则属性之间使用_强制进行连接
@Repository
public interface UserRepository extends MongoRepository<User, String> {
}
@Autowired
private UserRepository userRepository;
//模糊查询
@Test
public void findUsersLikeName() {
//创建匹配器,即如何使用查询条件
ExampleMatcher matcher = ExampleMatcher.matching() //构建对象
.withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING) //改变默认字符串匹配方式:模糊查询
.withIgnoreCase(true); //改变默认大小写忽略方式:忽略大小写
User user = new User();
user.setName("三");
Example<User> userExample = Example.of(user, matcher);
List<User> userList = userRepository.findAll(userExample);
System.out.println(userList);
}
//分页查询
@Test
public void findUsersPage() {
Sort sort = Sort.by(Sort.Direction.DESC, "age");
//0为第一页
Pageable pageable = PageRequest.of(0, 10, sort);
//创建匹配器,即如何使用查询条件
ExampleMatcher matcher = ExampleMatcher.matching() //构建对象
.withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING) //改变默认字符串匹配方式:模糊查询
.withIgnoreCase(true); //改变默认大小写忽略方式:忽略大小写
User user = new User();
user.setName("三");
Example<User> userExample = Example.of(user, matcher);
//创建实例
Example<User> example = Example.of(user, matcher);
Page<User> pages = userRepository.findAll(example, pageable);
System.out.println(pages);
}
//修改
@Test
public void updateUser() {
User user = userRepository.findById("5ffbfe8197f24a07007bd6ce").get();
user.setName("张三_1");
user.setAge(25);
user.setEmail("883220990@qq.com");
User save = userRepository.save(user);
System.out.println(save);
}
//删除
@Test
public void delete() {
userRepository.deleteById("5ffbfe8197f24a07007bd6ce");
}