高并发下Redis会出现的问题:
- 缓存穿透
- 缓存雪崩
- 热点缓存
一、定义commons工程11-dubboCommons
(1) 创建工程
创建Maven的Java工程,并命名为11-dubboCommons
(2) 定义pom文件
- <groupId>com.abc</groupId>
- <artifactId>11-dubboCommons</artifactId>
- <version>1.0-SNAPSHOT</version>
-
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <maven.compiler.source>1.8</maven.compiler.source>
- <maven.compiler.target>1.8</maven.compiler.target>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <version>1.18.4</version>
- <scope>provided</scope>
- </dependency>
- </dependencies>
(3) 定义实体类
(4) 定义业务接口
(5) 将工程安装到本地库
运行Maven的install命令,将工程安装到本地版本库,以备其它工程使用
二、定义提供者11-provider-springboot
(1) 创建工程
创建一个Spring Boot工程,并重命名为11-provider-springboot
(2) 定义pom文件
A、添加dubbo与spring boot整合依赖
B、添加zkClient依赖
C、其它依赖
- dubboCommons依赖
- spring boot与redis整合依赖
- mybatis与spring boot整合依赖
- 数据源Druid依赖
- mysql驱动依赖
- slf4j-log4j12依赖
- spring-boot-starter-web依赖
- <groupId>com.abc</groupId>
- <artifactId>11-provider-springboot</artifactId>
- <version>0.0.1-SNAPSHOT</version>
-
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>2.1.5.RELEASE</version>
- <relativePath/> <!-- lookup parent from repository -->
- </parent>
-
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
- <java.version>1.8</java.version>
- </properties>
-
- <dependencies>
- <!--dubbo与spring boot整合依赖-->
- <dependency>
- <groupId>com.alibaba.spring.boot</groupId>
- <artifactId>dubbo-spring-boot-starter</artifactId>
- <version>2.0.0</version>
- </dependency>
- <!-- zk客户端依赖:zkclient -->
- <dependency>
- <groupId>com.101tec</groupId>
- <artifactId>zkclient</artifactId>
- <version>0.10</version>
- </dependency>
- <dependency>
- <groupId>com.abc</groupId>
- <artifactId>11-dubboCommons</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <!--Spring Boot与Redis整合依赖-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-redis</artifactId>
- </dependency>
- <!--mybatis与Spring Boot整合依赖-->
- <dependency>
- <groupId>org.mybatis.spring.boot</groupId>
- <artifactId>mybatis-spring-boot-starter</artifactId>
- <version>1.3.2</version>
- </dependency>
- <!--数据源Druid依赖-->
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid</artifactId>
- <version>1.1.10</version>
- </dependency>
- <!--MySQL驱动依赖-->
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>5.1.47</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.7.25</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
-
- <resources>
- <!--注册dao包下mybatis映射文件为资源目录-->
- <resource>
- <directory>src/main/java</directory>
- <includes>
- <include>**/*.xml</include>
- </includes>
- </resource>
- </resources>
- </build>
(3) 定义Service实现类
- import com.abc.bean.Employee;
- import com.abc.dao.EmployeeDao;
- import com.alibaba.dubbo.config.annotation.Service;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.cache.annotation.CacheEvict;
- import org.springframework.cache.annotation.Cacheable;
- import org.springframework.data.redis.core.BoundValueOperations;
- import org.springframework.data.redis.core.RedisTemplate;
- import org.springframework.stereotype.Component;
- import org.springframework.transaction.annotation.Transactional;
-
- import java.util.concurrent.TimeUnit;
-
- @Service // Dubbo的注解 <dubbo:service/>
- @Component
- public class EmployeeServiceImpl implements EmployeeService {
- @Autowired
- private EmployeeDao dao;
- @Autowired
- private RedisTemplate<Object, Object> redisTemplate;
-
- // 当有对象插入时会清空realTimeCache缓存空间
- @CacheEvict(value="realTimeCache", allEntries = true)
- @Transactional(rollbackFor = Exception.class)
- @Override
- public void addEmployee(Employee employee) {
- dao.insertEmployee(employee);
- }
-
- // 一旦有了查询结果,则会将此结果写入到realTimeCache缓存
- // key是employee_加上方法参数
- @Cacheable(value = {"realTimeCache"}, key = "'employee_'+#id")
- @Override
- public Employee findEmployeeById(int id) {
- // 从DB查询
- System.out.println("从DB查询id = " + id);
- return dao.selectEmployeeById(id);
- }
-
- private volatile Object count;
- // 双重检测锁机制解决Reids的热点缓存问题
- @Override
- public Integer findEmployeeCount() {
- // 获取Redis操作对象
- BoundValueOperations<Object, Object> ops = redisTemplate.boundValueOps("count");
- // 从缓存获取数据
- count = ops.get();
- if(count == null) {
- synchronized (this) {
- count = ops.get();
- if(count == null) {
- System.out.println("从DB中查询");
- // 从DB中查询
- count = dao.selectEmployeeCount();
- // 将查询结果存放到Redis
- ops.set(count, 10, TimeUnit.SECONDS);
- }
- }
- }
- return (Integer) count;
- }
- }
(4) 定义Dao接口
(5) 定义映射文件
(6) 修改启动类
在启动类上必须要添加@EnableDubboConfiguration注解,开启Dubbo的自动配置功能
(7) 修改主配置文件
- server:
- port: 8888
-
- mybatis:
- # 注册mybatis中实体类的别名
- type-aliases-package: com.abc.bean
- # 注册映射文件
- mapper-locations: classpath:com/abc/dao/*.xml
-
- spring:
- # 注册数据源
- datasource:
- # 指定数据源类型为Druid
- type: com.alibaba.druid.pool.DruidDataSource
- driver-class-name: com.mysql.jdbc.Driver
- url: jdbc:mysql:///test?useUnicode=true&characterEncoding=utf8
- username: root
- password: root
-
- # 连接Redis服务器
- redis:
- host: 39.97.176.160
- port: 6379
-
- # 连接Redis高可有集群
- # redis:
- # sentinel:
- # master: mymaster
- # nodes:
- # - sentinelOS1:26379
- # - sentinelOS2:26379
- # - sentinelOS3:26379
-
- # 配置缓存
- cache:
- type: redis # 指定缓存类型
- cache-names: realTimeCache # 指定缓存区域名称
-
-
- # 功能等价于spring-boot配置文件中的<dubbo:application/>
- application:
- name: 11-provider-springboot
- # 指定zk注册中心
- dubbo:
- registry: zookeeper://39.97.176.160:2181
- # zk集群作注册中心
- # registry: zookeeper://zkOS1:2181?backup=zkOS2:2181,zkOS3:2181
三、定义消费者11-consumer-springboot
(1) 创建工程
创建一个Spring Boot工程,并重命名为11-consumer-springboot
(2) 定义pom文件
- dubbo与spring boot整合依赖
- zkClient依赖
- dubboCommons依赖
- JSP引擎jasper依赖
- slf4j-log4j12依赖
- spring-boot-starter-web依赖
(3) 修改主配置文件
- spring:
- # 功能等价于spring-dubbo配置文件中的<dubbo:application/>
- application:
- name: 11-consumer-springboot
- # 指定zk注册中心
- dubbo:
- registry: zookeeper://39.97.176.160:2181
- # zk集群作注册中心
- # registry: zookeeper://zkOS1:2181?backup=zkOS2:2181,zkOS3:2181
(4) 创建index.jsp页面
在src/main/webapp目录下定义index.jsp文件
(5) 定义处理器
- package com.abc.controller;
-
- import com.abc.bean.Employee;
- import com.abc.service.EmployeeService;
- import com.alibaba.dubbo.config.annotation.Reference;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.web.bind.annotation.PathVariable;
- import org.springframework.web.bind.annotation.PostMapping;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.ResponseBody;
-
- @Controller
- @RequestMapping("/consumer/employee")
- public class SomeController {
-
- // @Autowired
- @Reference // Dubbo的注解 <dubbo:reference />
- private EmployeeService employeeService;
-
- @PostMapping("/register")
- public String someHandle(Employee employee, Model model) {
- employeeService.addEmployee(employee);
- model.addAttribute("employee", employee);
- return "/welcome.jsp";
- }
-
- @RequestMapping("/find/{id}")
- @ResponseBody
- public Employee findHandle(@PathVariable("id") int id) {
- return employeeService.findEmployeeById(id);
- }
-
- @RequestMapping("/count")
- @ResponseBody
- public Integer countHandle() {
- return employeeService.findEmployeeCount();
- }
-
- }
(6) 定义welcome.jsp页面
(7) 修改入口类
四、测试
当有对象插入时会清空realTimeCache缓存空间
一旦有了查询结果,则会将此结果写入到realTimeCache缓存
http://localhost:8080/index.jsp 首页