자바 시 뮬 레이 션 및 캐 시 관통 문제 해결

21762 단어 자바캐 시꿰뚫다
캐 시 관통 이 라 니 요?
캐 시 관통 은 높 은 동시 다발 에서 만 발생 합 니 다.10000 개가 동시 다발 로 데 이 터 를 조회 할 때 우 리 는 보통 redis 에 가서 데 이 터 를 조회 합 니 다.그러나 redis 에 이 데이터 가 없 을 때 이 10000 개의 동시 다발 안에 많은 부분 이 한꺼번에 my sql 데이터베이스 에 가서 조회 합 니 다.
캐 시 관통 해결
우선 캐 시 관통 시 뮬 레이 션 을 해 보 겠 습 니 다.
예 를 들 어 아래 코드.

Pom.xml 코드

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.example</groupId>
 <artifactId>springboot</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>
 <name>springboot</name>
 <description>Demo project for Spring Boot</description>
 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.1.1.RELEASE</version>
  <relativePath></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>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-devtools</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
  </dependency>
  <dependency>
   <groupId>org.mybatis.spring.boot</groupId>
   <artifactId>mybatis-spring-boot-starter</artifactId>
   <version>1.1.1</version>
  </dependency>
  <dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
  </dependency>
 </dependencies>
 <build>
  <plugins>
   <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
   </plugin>
  </plugins>
 </build>
</project>
Application.properties
server.port=8081
#DB Configuration:
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://47.91.248.236:3306/hello?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root
#spring  Mybatis  
#pojo     
mybatis.type-aliases-package=com.itheima.domain
#  Mybatis    
mybatis.mapper-locations=classpath:mapper/*Mapper.xml
MyController  ,          10000     
/**
 * sinture.com Inc.
 * Copyright (c) 2016-2018 All Rights Reserved.
 */
package com.itheima.controller;
import com.itheima.mapper.UserMapper;
import com.itheima.domain.User;
import com.itheima.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @author xinzhu
 * @version Id: MyController.java, v 0.1 2018 12 05    6:29 xinzhu Exp $
 */
@RestController
public class MyController {
 @Autowired
 private UserService userService;
 @RequestMapping("/hello/{id}")
 @ResponseBody
 public User queryUser(@PathVariable Integer id){
  //         
  new Thread(){
   @Override
   public void run() {
    for (int x = 0; x < 10000; x++) {
     userService.queryUser(id);
    }
   }
  }.start();
  //         
  return userService.queryUser(id);
 }
}
사용자 클래스

/**
 * sinture.com Inc.
 * Copyright (c) 2016-2018 All Rights Reserved.
 */
package com.itheima.domain;
/**
 * @author xinzhu
 * @version Id: User.java, v 0.1 2018 12 06    1:40 xinzhu Exp $
 */
public class User {
 //   
 private Integer id;
 //    
 private String username;
 //   
 private String password;
 //   
 private String name;
 public void setId(Integer id) {
  this.id = id;
 }
 @Override
 public String toString() {
  return "User{" +
    "id=" + id +
    ", username='" + username + '\'' +
    ", password='" + password + '\'' +
    ", name='" + name + '\'' +
    '}';
 }
 public Integer getId() {
  return id;
 }
 public String getUsername() {
  return username;
 }
 public void setUsername(String username) {
  this.username = username;
 }
 public String getPassword() {
  return password;
 }
 public void setPassword(String password) {
  this.password = password;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
}
UserService
package com.itheima.service;
import com.itheima.domain.User;
public interface UserService {
 public User queryUser(Integer id);
}
UserServiceImpl,아래 의 파란색 코드 는 redis 를 모방 하 는 것 입 니 다.이때 아래 의 아 날로 그 redis 의 map 집합 은 아래 query User 의 밖 에 놓 아야 합 니 다.즉,아래 의 userMap 변 수 는 반드시 구성원 변수 여야 합 니 다.그렇지 않 으 면 redis 는 여러 스 레 드 에 의 해 공유 되 기 때 문 입 니 다.아래 의 query User()방법 에 넣 으 면...그러면 여러 스 레 드 에 여러 개의 userMap 집합 이 있 습 니 다.아래 코드 는 데 이 터 를 조회 하면 redis 안에 있 는 것 을 사용 하고 조회 가 안 되면 데이터 베이스 에 있 는 것 을 사용 하 는 것 입 니 다.

package com.itheima.service;
import com.itheima.domain.User;
import com.itheima.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
public class UserServiceImpl implements UserService {
 @Autowired
 private UserMapper userMapper;
 //         
 static Map<Integer,User> userMap=new HashMap();
 static {
  User huancun_user =new User();
  huancun_user.setId(1);
  huancun_user.setName("zhangsan");
  huancun_user.setPassword("123");
  huancun_user.setName("  ");
  userMap.put(1,huancun_user);
 }
 //         
 public User queryUser(Integer id){
  User user=userMap.get(id);
  if(user==null){
   user= userMapper.queryUser(id);
   System.out.println("     ");
   userMap.put(user.getId(),user);
  }else{
   System.out.println("    ");
  }
  return user;
 };
}
SpringbootApplication  
package com.itheima;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootApplication {
 public static void main(String[] args) {
  SpringApplication.run(SpringbootApplication.class, args);
 }
}
데이터베이스 안의 데 이 터 는 다음 과 같다.

-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `username` varchar(50) DEFAULT NULL,
 `password` varchar(50) DEFAULT NULL,
 `name` varchar(50) DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'zhangsan', '123', '  ');
INSERT INTO `user` VALUES ('2', 'lisi', '123', '  ');
그 다음 에 우 리 는 아래 의 링크 를 조회 합 니 다.이때 위의 아 날로 그 redis 의 map 집합 에 id 값 이 2 인 데이터 가 없 기 때문에 이때 모두 데이터 베 이 스 를 조회 합 니 다.이번에 10000 을 동시 다발 하면 데이터 베 이 스 는 매우 큰 스트레스 를 받 을 것 이 라 고 생각 합 니 다.

그 다음 에 인쇄 결 과 는 다음 과 같다.바로 많은 조회 데이터 베이스 와 조회 캐 시 를 인쇄 한 것 이다.이때 10000 개의 동시 다발 안에 데이터 베 이 스 를 조회 하 는 경우 가 많다 는 것 을 의미한다.이것 은 피해 야 한다.왜 캐 시 를 조회 하 는 인쇄 가 있 는 지 에 대해 우 리 는 조회 한 데 이 터 를 아 날로 그 redis 에 넣 었 기 때문에 처음에 대부분의 스 레 드 는 데이터 베 이 스 를 조회 하 는 것 이다.그리고 나머지 는 아 날로 그 redis 캐 시 에 있 는 데 이 터 를 조회 하 는 것 입 니 다.
조회 데이터베이스
조회 데이터베이스
조회 데이터베이스
조회 데이터베이스
조회 데이터베이스
조회 데이터베이스
조회 데이터베이스
조회 데이터베이스
조회 데이터베이스
조회 데이터베이스
조회 데이터베이스
조회 데이터베이스
조회 데이터베이스
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
그리고 우 리 는 이중 검 측 자 물 쇠 를 사용 하여 위의 캐 시 관통 을 해결 합 니 다.
우 리 는 캐 시 관통 을 어떻게 해결 합 니까?10000 개가 병발 되 더 라 도 10000 개의 병발 에 필요 한 데 이 터 는 redis 에 없습니다.그러면 우 리 는 첫 번 째 스 레 드 로 데이터 안의 데 이 터 를 조회 한 다음 에 이 데 이 터 를 redis 에 넣 고 나머지 9999 개의 스 레 드 를 redis 에 넣 어서 조회 해 야 합 니 다.그러면 캐 시 관통 을 해결 할 수 있 습 니 다.그래서 우 리 는 위의 코드 를 아래 처럼 바 꿀 수 있다.
예 를 들 어 아래 코드.

Pom.xml 코드

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.example</groupId>
 <artifactId>springboot</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>
 <name>springboot</name>
 <description>Demo project for Spring Boot</description>
 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.1.1.RELEASE</version>
  <relativePath></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>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-devtools</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
  </dependency>
  <dependency>
   <groupId>org.mybatis.spring.boot</groupId>
   <artifactId>mybatis-spring-boot-starter</artifactId>
   <version>1.1.1</version>
  </dependency>
  <dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
  </dependency>
 </dependencies>
 <build>
  <plugins>
   <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
   </plugin>
  </plugins>
 </build>
</project>
Application.properties
server.port=8081
#DB Configuration:
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://47.91.248.236:3306/hello?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root
#spring  Mybatis  
#pojo     
mybatis.type-aliases-package=com.itheima.domain
#  Mybatis    
mybatis.mapper-locations=classpath:mapper/*Mapper.xml
MyController 코드,아래 파란색 코드 는 10000 개의 병렬 스 레 드 를 모방 합 니 다.

/**
 * sinture.com Inc.
 * Copyright (c) 2016-2018 All Rights Reserved.
 */
package com.itheima.controller;
import com.itheima.mapper.UserMapper;
import com.itheima.domain.User;
import com.itheima.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @author xinzhu
 * @version Id: MyController.java, v 0.1 2018 12 05    6:29 xinzhu Exp $
 */
@RestController
public class MyController {
 @Autowired
 private UserService userService;
 @RequestMapping("/hello/{id}")
 @ResponseBody
 public User queryUser(@PathVariable Integer id){
  //         
  new Thread(){
   @Override
   public void run() {
    for (int x = 0; x < 10000; x++) {
     userService.queryUser(id);
    }
   }
  }.start();
  //         
  return userService.queryUser(id);
 }
}
User 
/**
 * sinture.com Inc.
 * Copyright (c) 2016-2018 All Rights Reserved.
 */
package com.itheima.domain;
/**
 * @author xinzhu
 * @version Id: User.java, v 0.1 2018 12 06    1:40 xinzhu Exp $
 */
public class User {
 //   
 private Integer id;
 //    
 private String username;
 //   
 private String password;
 //   
 private String name;
 public void setId(Integer id) {
  this.id = id;
 }
 @Override
 public String toString() {
  return "User{" +
    "id=" + id +
    ", username='" + username + '\'' +
    ", password='" + password + '\'' +
    ", name='" + name + '\'' +
    '}';
 }
 public Integer getId() {
  return id;
 }
 public String getUsername() {
  return username;
 }
 public void setUsername(String username) {
  this.username = username;
 }
 public String getPassword() {
  return password;
 }
 public void setPassword(String password) {
  this.password = password;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
}
UserService
package com.itheima.service;
import com.itheima.domain.User;
public interface UserService {
 public User queryUser(Integer id);
}
UserServiceImpl,아래 의 파란색 코드 는 redis 를 모방 하 는 것 입 니 다.이때 아래 의 아 날로 그 redis 의 map 집합 은 아래 query User 의 밖 에 놓 아야 합 니 다.즉,아래 의 userMap 변 수 는 반드시 구성원 변수 여야 합 니 다.그렇지 않 으 면 redis 는 여러 스 레 드 에 의 해 공유 되 기 때 문 입 니 다.아래 의 query User()방법 에 넣 으 면...그러면 여러 스 레 드 에 여러 개의 userMap 집합 이 있 습 니 다.아래 코드 는 데 이 터 를 조회 하면 redis 안에 있 는 것 을 사용 하고 조회 가 안 되면 데이터 베이스 에 있 는 것 을 사용 하 는 것 입 니 다.
그 다음 에 아래 의 빨간색 코드 는 바로 위의 캐 시 관통 문 제 를 해결 하 는 것 입 니 다.자 물 쇠 를 사용 하여 캐 시 관통 문 제 를 해결 하 는 것 입 니 다.그리고 이중 검 측 자물쇠 라 고 합 니 다.왜 이중 검 측 자물쇠 라 고 합 니까?두 개의 if 문구 가 있 기 때문에 첫 번 째 if 문 구 는 빨간색 코드 안의 동기 코드 블록 을 줄 이기 위해 서 입 니 다.안에 원 하 는 데이터 가 존재 하기 때 문 입 니 다.그러면 아래 의 빨간색 코드 에 있 는 동기 코드 블록 을 걸 을 필요 가 없습니다.그래서 두 개의 if 문구 가 있 습 니 다.왜 아래 의 user=userMap.get(id)이 있어 야 하 는 지 에 대해 서 는...첫 번 째 스 레 드 조회 에서 데 이 터 를 모방 한 redis 캐 시 에 넣 은 후에 남 은 스 레 드 가 아래 의 동기 코드 블록 으로 갈 때 캐 시 에 있 는 데 이 터 를 조회 해 야 방금 첫 번 째 스 레 드 가 redis 에 있 는 데 이 터 를 발견 할 수 있 기 때문에 아래 의 빨간색 코드 에 있 는 user=userMap.get(id)이 있 습 니 다.

package com.itheima.service;
import com.itheima.domain.User;
import com.itheima.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
public class UserServiceImpl implements UserService {
 @Autowired
 private UserMapper userMapper;
 //         
 static Map<Integer,User> userMap=new HashMap();
 static {
  User huancun_user =new User();
  huancun_user.setId(1);
  huancun_user.setName("zhangsan");
  huancun_user.setPassword("123");
  huancun_user.setName("  ");
  userMap.put(1,huancun_user);
 }
 //         
 public User queryUser(Integer id){
  User user=userMap.get(id);
  //         
  if(user==null){
   synchronized (this) {
    user= userMap.get(id);
    if (null == user) {
     user= userMapper.queryUser(id);
     System.out.println("     ");
     userMap.put(user.getId(),user);
    }else{
     System.out.println("    ");
    }
   }
  }else{
   System.out.println("    ");
  }
  //        
  return user;
 };
}
데이터베이스 안의 데 이 터 는 다음 과 같다.

-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `username` varchar(50) DEFAULT NULL,
 `password` varchar(50) DEFAULT NULL,
 `name` varchar(50) DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'zhangsan', '123', '  ');
INSERT INTO `user` VALUES ('2', 'lisi', '123', '  ');
그 다음 에 우 리 는 아래 의 링크 를 조회 합 니 다.이때 위의 아 날로 그 redis 의 map 집합 에 id 값 이 2 인 데이터 가 없 기 때문에 이때 모두 데이터 베 이 스 를 조회 합 니 다.이번에 10000 을 동시 다발 하면 데이터 베 이 스 는 매우 큰 스트레스 를 받 을 것 이 라 고 생각 합 니 다.
 
그리고 인쇄 결 과 는 다음 과 같 습 니 다.바로 첫 번 째 로 조회 데이터 베 이 스 를 인쇄 한 다음 에 나머지 는 모두 캐 시 를 조회 하 는 것 입 니 다.이것 이 바로 캐 시 관통 을 해결 하 는 것 입 니 다.
조회 데이터베이스
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
캐 시 조회
총결산
위 에서 말 한 것 은 편집장 이 여러분 에 게 소개 한 자바 시 뮬 레이 션 과 캐 시 관통 문 제 를 해결 하 는 것 입 니 다.여러분 에 게 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 면 메 시 지 를 남 겨 주세요.편집장 은 신속하게 답 해 드 리 겠 습 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!
만약 당신 이 본문 이 당신 에 게 도움 이 된다 고 생각한다 면,전 재 를 환영 합 니 다.번 거 로 우 시 겠 지만 출처 를 밝 혀 주 십시오.감사합니다!

좋은 웹페이지 즐겨찾기