目录
一、整合Druid
1. Druid是什么?
2.如何在Spring Boot中集成Druid连接池和监控?
二、整合Redis
1.集成redis之非注解式开发
2.集成redis之注解缓存开发
一、整合Druid
1. Druid是什么?
Druid是Java语言中最好的数据库连接池。Druid能够提供强大的监控和扩展功能。
2.如何在Spring Boot中集成Druid连接池和监控?
参考地址:
druid/druid-spring-boot-starter at master · alibaba/druid · GitHub阿里云计算平台DataWorks(https://help.aliyun.com/document_detail/137663.html) 团队出品,为监控而生的数据库连接池 - druid/druid-spring-boot-starter at master · alibaba/druidhttps://github.com/alibaba/druid/tree/master/druid-spring-boot-starter
这里我们就不创建新的项目了,在上一节的博客项目中,进行添加配置如下:
添加配置,不要最新的,否则进行测试SQL监控失效 pom.xml
<!-- 添加druid相关的依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
application.yml
mybatis:
mapper-locations: classpath:mappers/*xml
type-aliases-package: com.jwj.spring04.model
server:
port: 8080
servlet:
context-path: /spring04
spring:
application:
name: spring04
datasource:
driver-class-name: com.mysql.jdbc.Driver
name: defaultDataSource
password: 123456
url: jdbc:mysql://localhost:3306/mybatis_ssm?useUnicode=true&characterEncoding=UTF-8
username: root
type: com.zaxxer.hikari.util.DriverDataSource
druid:
#2.连接池配置
#初始化连接池的连接数量 大小,最小,最大
initial-size: 5
min-idle: 5
max-active: 20
#配置获取连接等待超时的时间
max-wait: 60000
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runs-millis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
min-evictable-idle-time-millis: 30000
validation-query: SELECT 1 FROM DUAL
test-while-idle: true
test-on-borrow: true
test-on-return: false
# 是否缓存preparedStatement,也就是PSCache 官方建议MySQL下建议关闭 个人建议如果想用SQL防火墙 建议打开
pool-prepared-statements: true
max-pool-prepared-statement-per-connection-size: 20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filter:
stat:
merge-sql: true
slow-sql-millis: 5000
#3.基础监控配置
web-stat-filter:
enabled: true
url-pattern: /*
#设置不统计哪些URL
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
session-stat-enable: true
session-stat-max-count: 100
stat-view-servlet:
enabled: true
url-pattern: /druid/*
reset-enable: true
#设置监控页面的登录名和密码
login-username: admin
login-password: admin
allow: 127.0.0.1
#deny: 192.168.1.100
freemarker:
cache: false
charset: utf-8
expose-request-attributes: true
expose-session-attributes: true
suffix: .ftl
template-loader-path: classpath:/templates/
# resources:
# static-locations: classpath:/static/# 应用服务 WEB 访问端口
mvc:
static-path-pattern: classpath:/static/
pagehelper:
reasonable: true
supportMethodsArguments: true
page-size-zero: true
helper-dialect: mysql
# 可以在控制台中展示SQL语句
logging:
level:
com.zking.spring04: debug
登录进去后:因为在yml中设置了本地访问,如果我们设置的是不允许本地访问这个页面是看不到
二、整合Redis
1.集成redis之非注解式开发
如果要重新创建项目,把Spring data 组件勾选上,在把其他的勾选上,就集成好了。
这里我就用到上面的。我就直接在pom.xml添加redis相关依赖
<!-- 添加redis相关集成依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
开启我们的虚假机,把redis启动。
application.yml相关配置
mybatis:
mapper-locations: classpath:mappers/*xml
type-aliases-package: com.jwj.spring04.model
server:
port: 8080
servlet:
context-path: /spring04
spring:
application:
name: spring04
datasource:
driver-class-name: com.mysql.jdbc.Driver
name: defaultDataSource
password: 123456
url: jdbc:mysql://localhost:3306/mybatis_ssm?useUnicode=true&characterEncoding=UTF-8
username: root
type: com.zaxxer.hikari.util.DriverDataSource
druid:
#2.连接池配置
#初始化连接池的连接数量 大小,最小,最大
initial-size: 5
min-idle: 5
max-active: 20
#配置获取连接等待超时的时间
max-wait: 60000
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runs-millis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
min-evictable-idle-time-millis: 30000
validation-query: SELECT 1 FROM DUAL
test-while-idle: true
test-on-borrow: true
test-on-return: false
# 是否缓存preparedStatement,也就是PSCache 官方建议MySQL下建议关闭 个人建议如果想用SQL防火墙 建议打开
pool-prepared-statements: true
max-pool-prepared-statement-per-connection-size: 20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filter:
stat:
merge-sql: true
slow-sql-millis: 5000
#3.基础监控配置
web-stat-filter:
enabled: true
url-pattern: /*
#设置不统计哪些URL
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
session-stat-enable: true
session-stat-max-count: 100
stat-view-servlet:
enabled: true
url-pattern: /druid/*
reset-enable: true
#设置监控页面的登录名和密码
login-username: admin
login-password: admin
allow: 127.0.0.1
#deny: 192.168.1.100
freemarker:
cache: false
charset: utf-8
expose-request-attributes: true
expose-session-attributes: true
suffix: .ftl
template-loader-path: classpath:/templates/
# resources:
# static-locations: classpath:/static/# 应用服务 WEB 访问端口
mvc:
static-path-pattern: classpath:/static/
redis:
host: 192.168.29.128
port: 6379
database: 0
password: 123456
pagehelper:
reasonable: true
supportMethodsArguments: true
page-size-zero: true
helper-dialect: mysql
# 可以在控制台中展示SQL语句
logging:
level:
com.zking.spring04: debug
redisTemplate 这里默认Springboot是没有设置管理redistemplate
我们要做的:将redistemplate进行配置,然后交给spring进行管理。
配置类RedisConfig.java
package com.jwj.spring04.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* @author 敢敢
* @site www.javajwj.com
* @company xxx公司
* @create 2022-11-26 10:45
*
* @Configuration:凡是被@Configuration注解所标记的就代表当前这个类为配置类
* 而配置类等价于ssm阶段中spring-*.xml 这一类的配置文件
*
* 我们要做的:将redistemplate进行配置,然后交给spring进行管理。
*/
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String,Object> getRedisTemplate(RedisConnectionFactory connectionFactory){
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// 配置序列化器 分两块
// 针对于key
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
// 针对于value
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
// redisTemplate.afterPropertiesSet();// 根据不同的redis版本决定这个要不要写
// 如果上面的不生效就写这个 ,让这个配置生效
// connectionFactory 是包含了redis的连接信息
redisTemplate.setConnectionFactory(connectionFactory);
return redisTemplate;
}
}
Clazz.java
package com.jwj.spring04.model;
import java.io.Serializable;
/**
* NotNull:针对的是基本数据类型
* @NotEmpty 作用于集合
* @NotBlank 作用于字符串
*/
public class Clazz implements Serializable {
protected Integer cid;
protected String cname;
protected String cteacher;
protected String pic;
public Clazz(Integer cid, String cname, String cteacher, String pic) {
this.cid = cid;
this.cname = cname;
this.cteacher = cteacher;
this.pic = pic;
}
public Clazz() {
super();
}
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public String getCteacher() {
return cteacher;
}
public void setCteacher(String cteacher) {
this.cteacher = cteacher;
}
public String getPic() {
return pic;
}
public void setPic(String pic) {
this.pic = pic;
}
}
biz层ClazzBizImpl.java
package com.jwj.spring04.biz.impl; import com.jwj.spring04.biz.ClazzBiz; import com.jwj.spring04.mapper.ClazzMapper; import com.jwj.spring04.model.Clazz; import com.jwj.spring04.util.PageBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import java.util.List; import java.util.Map; /** * @author小李飞刀 * @site www.javaxl.com * @company xxx公司 * @create 2022-08-17 15:13 */ @Service public class ClazzBizImpl implements ClazzBiz { @Autowired private ClazzMapper clazzMapper; @Autowired private RedisTemplate<String,Object> redisTemplate; @Override public int deleteByPrimaryKey(Integer cid) { System.out.println("不做任何操作..."); return clazzMapper.deleteByPrimaryKey(cid); // return 0; } @Override public int insert(Clazz record) { return clazzMapper.insert(record); } @Override public int insertSelective(Clazz record) { return clazzMapper.insertSelective(record); } @Override public Clazz selectByPrimaryKey(Integer cid) { return clazzMapper.selectByPrimaryKey(cid); } @Override public int updateByPrimaryKeySelective(Clazz record) { return clazzMapper.updateByPrimaryKeySelective(record); } @Override public int updateByPrimaryKey(Clazz record) { return clazzMapper.updateByPrimaryKey(record); } @Override public List<Clazz> listPager(Clazz clazz, PageBean pageBean) { List<Clazz> clazzes = clazzMapper.listPager(clazz); // 将班级信息缓存到redis 中 redisTemplate.opsForValue().set("clz_infos",clazzes); return clazzes; } @Override public List<Map> listMapPager(Clazz clazz, PageBean pageBean) { if(true) throw new RuntimeException("查询班级信息异常,异常存在于ClazzBizImpl.list。。。。"); return clazzMapper.listMapPager(clazz); } }
运行效果如下图所示:
2.集成redis之注解缓存开发
RedisConfig.java
package com.jwj.spring04.config; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.StringRedisSerializer; import java.time.Duration; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; /** * @author 敢敢 * @site www.javajwj.com * @company xxx公司 * @create 2022-11-26 10:45 * * @Configuration:凡是被@Configuration注解所标记的就代表当前这个类为配置类 * 而配置类等价于ssm阶段中spring-*.xml 这一类的配置文件 * * 我们要做的:将redistemplate进行配置,然后交给spring进行管理。 * @EnableCaching 替代了下面的配置 开启注解/开启缓存 */ @EnableCaching @Configuration public class RedisConfig { private final int defaultExpireTime = 600; private final int userCacheExpireTime = 60; private final String userCacheName = "test"; @Bean public RedisTemplate<String,Object> getRedisTemplate(RedisConnectionFactory connectionFactory){ RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); // 配置序列化器 分两块 // 针对于key redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); // 针对于value redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); // redisTemplate.afterPropertiesSet();// 根据不同的redis版本决定这个要不要写 // 如果上面的不生效就写这个 ,让这个配置生效 // connectionFactory 是包含了redis的连接信息 redisTemplate.setConnectionFactory(connectionFactory); return redisTemplate; } @Bean public RedisCacheManager redis(RedisConnectionFactory connectionFactory){ RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig(); // 设置缓存管理器管理的缓存的默认过期时间 defaultCacheConfig = defaultCacheConfig.entryTtl(Duration.ofSeconds(defaultExpireTime)) // 设置 key为string序列化 .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) // 设置value为json序列化 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())) // 不缓存空值 .disableCachingNullValues(); Set<String> cacheNames = new HashSet<>(); cacheNames.add(userCacheName); // 对每个缓存空间应用不同的配置 Map<String, RedisCacheConfiguration> configMap = new HashMap<>(); configMap.put(userCacheName, defaultCacheConfig.entryTtl(Duration.ofSeconds(userCacheExpireTime))); RedisCacheManager cacheManager = RedisCacheManager.builder(connectionFactory) .cacheDefaults(defaultCacheConfig) .initialCacheNames(cacheNames) .withInitialCacheConfigurations(configMap) .build(); return cacheManager; } }
把ClazzBIzImpl.java 缓存注释掉了。
@Override
public List<Clazz> listPager(Clazz clazz, PageBean pageBean) {
List<Clazz> clazzes = clazzMapper.listPager(clazz);
// 将班级信息缓存到redis 中
// redisTemplate.opsForValue().set("clz_infos",clazzes);
return clazzes;
}
ClazzBiz.java
package com.jwj.spring04.biz;
import com.jwj.spring04.model.Clazz;
import com.jwj.spring04.util.PageBean;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import java.util.List;
import java.util.Map;
public interface ClazzBiz {
@CacheEvict(value = "xx",key = "'cid:'+#cid",allEntries = true)
int deleteByPrimaryKey(Integer cid);
int insert(Clazz record);
int insertSelective(Clazz record);
@Cacheable(value = "test") //ttl时间为60s
Clazz selectByPrimaryKey(Integer cid);
int updateByPrimaryKeySelective(Clazz record);
int updateByPrimaryKey(Clazz record);
List<Clazz> listPager(Clazz clazz, PageBean pageBean);
List<Map> listMapPager(Clazz clazz, PageBean pageBean);
}
在ClazzController.java添加
@ResponseBody
@RequestMapping("/load")
public Clazz load(Clazz clazz, HttpServletRequest request){
return clazzBiz.selectByPrimaryKey(clazz.getCid());
}
package com.jwj.spring04.controller;
import com.jwj.spring04.biz.ClazzBiz;
import com.jwj.spring04.model.Clazz;
import com.jwj.spring04.util.PageBean;
import com.jwj.spring04.util.PageFreeMarker;
import org.apache.tomcat.util.http.fileupload.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("/clz")
public class ClazzController {
@Autowired
private ClazzBiz clazzBiz;
// list->clzList
// toList->重定向list->"redirect:/clz/list"
// toEdit->跳转到编辑界面->clzEdit
// Clazz : 以前是通过模型驱动接口封装,现在是直接在方法中接受参数即可
@RequestMapping("/list")
public String list(Clazz clazz, HttpServletRequest request){
System.out.println("我添加了 新的代码,终于不重启了....");
PageBean pageBean = new PageBean();
pageBean.setRequest(request);
List<Clazz> lst = this.clazzBiz.listPager(clazz, pageBean);
request.setAttribute("lst",lst);
request.setAttribute("pageBean",pageBean);
request.setAttribute("pagestr", PageFreeMarker.toHTML(pageBean));
return "clz/clzList";
}
@RequestMapping("/toEdit")
public String toEdit(Clazz clazz, HttpServletRequest request){
Integer cid = clazz.getCid();
// 传递的id代表了修改,没传代表新增
if(cid != null){
List<Clazz> lst = this.clazzBiz.listPager(clazz, null);
request.setAttribute("b",lst.get(0));
}
return "clz/clzEdit";
}
@ResponseBody
@RequestMapping("/load")
public Clazz load(Clazz clazz, HttpServletRequest request){
return clazzBiz.selectByPrimaryKey(clazz.getCid());
}
@RequestMapping("/add")
public String add(Clazz clazz){
this.clazzBiz.insertSelective(clazz);
return "redirect:/clz/list";
}
@RequestMapping("/edit")
public String edit(Clazz clazz){
this.clazzBiz.updateByPrimaryKeySelective(clazz);
return "redirect:/clz/list";
}
@RequestMapping("/del")
public String del(Clazz clazz){
this.clazzBiz.deleteByPrimaryKey(clazz.getCid());
return "redirect:/clz/list";
}
}
运行效果如图所示:
ClazzBiz.java
package com.jwj.spring04.biz;
import com.jwj.spring04.model.Clazz;
import com.jwj.spring04.util.PageBean;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import java.util.List;
import java.util.Map;
public interface ClazzBiz {
@CacheEvict(value = "xx",key = "'cid:'+#cid",allEntries = true)
int deleteByPrimaryKey(Integer cid);
int insert(Clazz record);
int insertSelective(Clazz record);
// @Cacheable(value = "test") //ttl时间为60s
@Cacheable(value = "clz",key = "'cid:'+#cid")
Clazz selectByPrimaryKey(Integer cid);
int updateByPrimaryKeySelective(Clazz record);
int updateByPrimaryKey(Clazz record);
List<Clazz> listPager(Clazz clazz, PageBean pageBean);
List<Map> listMapPager(Clazz clazz, PageBean pageBean);
}
运行效果:秒数就不一样了