첫째, 환경 springBoot :
1) 오기 의존성 :
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<의존성> <의 groupId> org.springframework.boot </의 groupId> <artifactId를> 스프링 부팅 스타터 데이터 레디 스 </ artifactId를> </ 의존성>
2)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
봄 : 레디 스 : 호스트 : 192.168.2.147 포트 : 6379 암호 : java1902의 jedis : 풀 : 최대 - 활동 : 100
데이터베이스 캐시 등 두, 레디 스 :
작동 방식 : 첫 번째 쿼리는 SQL에서 데이터가 변경, 빈 캐시 해당 레디 스를 재 취득 할 때까지 후속 쿼리에 대한 레디 스 데이터로 조회 완료 후, SQL 데이터베이스를 사용;
캐시 무효화 : 캐시 레디 스 방식을 빈 사용하여 데이터베이스를 업데이트;
1) 엔티티 클래스 :
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
공용 클래스 제품 구현 직렬화 { 개인 정수 ID를; 개인 문자열 이름; 대중 제품 () { } 공공 제품 (정수 ID, 문자열 이름) { 이 .ID = 아이디; 이 .name을 = 이름; } 공공 정수 getId () { 반환 아이디; } 공공 공극 setId (정수 ID) { 이 .ID = ID; } 공공 문자열 getName () { 반환 이름; } 공공 무효 에서는 setName (문자열 이름) { 이 .name을 = 이름; } @Override 공공 문자열 toString () { 반환 "제품 {"+ "ID ="+ 아이디 + ", 이름 = '"+ 이름 +'\ ''+ '}' ; } }
2) 시험 :
@RunWith (SpringRunner. 클래스 ) @SpringBootTest 공공 클래스 RedistestSpringData2ApplicationTests { @Autowired 개인 RedisTemplate redisTemplate을; @Test 공공 무효 cacheTest () { 목록 . <제품 소개> 제품 = (목록 <제품 소개>) redisTemplate.opsForValue () ( "제품"수 ); 경우 (제품 == null이 ) { 에서 System.out.println ( "查询数据库......" ); // 模拟从数据库查询数据 제품 = 새로운 ArrayList를 <제품 소개> (); products.add (새 제품 (1, "商品1" )); products.add ( 새 제품 (2, "商品2" )); redisTemplate.opsForValue () 세트 (. "제품" , 제품); } 다른 { 에서 System.out.println ( "查询缓存......" ); } } @Test 공공 무효 delCacheTest () { redisTemplate.delete ( "제품" ); } }
셋째, 해결 캐시 관통 질문 :
잃어버린 시간이 캐시에 기록되지 않은 데이터베이스 정보를 접속하여 스레드를 조각, 반복 방문 다른 스레드 데이터베이스 액세스, 데이터베이스는 엄청난 압력을 발생 ;: 이유
해결 방법 :
1) 잠금 동기화 :이 분산되어 있기 때문에 개발을 동기화 범위는 여러 서비스를 통해 동기화 된 JVM은 무효입니다;
2) 레디 스 분산 잠금 :
1, 레디 스 지방의 사용 :
setnx 잠금 1 // 1 GET 잠금 // 1 잠금 setnx 2 // 00 델 잠금 setnx 잠금 2 // 1
2, springboot 코드 구현 :
// 마지막으로 시도 교착 상태 문제를 해결 :
@RunWith (SpringRunner. 클래스 ) @SpringBootTest 공공 클래스 RedistestSpringData2ApplicationTests { @Autowired 개인 RedisTemplate redisTemplate을; @Test 공개 공극 multiThreadTest () 가 발생 예외 : InterruptedException { ExecutorService를 풀 = 새로운 ThreadPoolExecutor에 (100, 200, 100 , TimeUnit.MILLISECONDS, 새로운 LinkedBlockingDeque를 <> (100 ))을 위한 ( int로 , I (100) <; I = 0 난 ++ ) { pool.submit를 ( 새로운 의 Runnable () { @Override 공공 무효 실행 () { cacheTest (); } }); } 에 Thread.sleep ( 1000000 ); } @Test 공공 무효 cacheTest () { 목록 . <제품 소개> 제품 = (목록 <제품 소개>) redisTemplate.opsForValue () ( "제품"수 ); 경우 (제품 == 널 ) { 부울 ifAbsent = redisTemplate.opsForValue () setIfAbsent. ( "제품 : 잠금", 1 ); 경우 (ifAbsent) { 시도 { 에서 System.out.println ( "데이터베이스 쿼리 ......" ); // 데이터베이스 쿼리에서 아날로그 데이터 제품 = 새로운 새로운 ArrayList를 <제품 소개> (); products.add ( 새 새 제품 (1, "제품 1" )) ; products.add ( 새 새 제품 (2, "제품 2" )); int로 내가 = 10/0 ; redisTemplate.opsForValue () SET (. : "제품" ;, 제품) } 최종적으로 { redisTemplate.delete ( "제품 : "잠금 ); } } 다른 { 시도 { Thread.sleep를 ( 1 ); } 캐치 (예외 : InterruptedException 전자) { e.printStackTrace (); } cacheTest (); } } 다른 { 에서 System.out.println ( "查询缓存......" ); } } @Test 공공 무효 delCacheTest () { redisTemplate.delete ( "제품" ); } }
넷째, 캐시 고장의 문제를 해결하기 위해 :
그 이유는 반복되는 쿼리마다 다시 액세스 데이터베이스 널;
해결 방법 : 값이 null 쿼리가 캐시로 레디 스에 빈 객체를 반환, 일정 시간이 만료 설정;
@RunWith (SpringRunner. 클래스 ) @SpringBootTest 공공 클래스 RedistestSpringData2ApplicationTests { @Autowired 개인 RedisTemplate redisTemplate을; 공공 제품 productById (정수 ID) { 경우 (ID> 10 ) { 반환 널 (null) ; } 반환 새 ) (제품; } @Test 공개 공극 cachePenetrationTest () { 위해 ( int로 난 = 11, I <20; i가 ++ ) { 제품 일반= (제품) redisTemplate.opsForValue () GET ( "제품". + I), IF (제품 == null이 ) { // 데이터베이스 쿼리에서 아날로그 데이터 에서 System.out.println ( "데이터베이스 쿼리 ...... " ); // i가 10보다 큰 경우, 입력이 null 제품 = productById (I) // 빈 경우는 null 때 IF (제품 == 널 ) { 제품 = 새로운 새로운 생성물 (I" " ); redisTemplate. . opsForValue () SET ( "제품"+ I, 제품); redisTemplate.expire ("제품"+ I, 10 , TimeUnit.MINUTES); } 다른 { . redisTemplate.opsForValue () 세트 ( 이하 "제품"+ I, 제품); redisTemplate.expire ( 이하 "제품"+ I, 20 , TimeUnit.MINUTES); } } 다른 { 에서 System.out.println ( "查询缓存......" ); } } } @Test 공공 무효 delCacheTest () { redisTemplate.delete ( "제품" ); } }