7.1 매일 자정에 날씨 데이터 불러오기
캐싱(Caching)이란?
- 캐싱은 캐시(cache)라는 빠른 메모리 영역으로 데이터를 가져와서 접근하는 방식을 말한다.
- 데이터 등을 미리 복사해서 저장해두는 것을 말한다.
- 요청을 빠르게 처리한다.
- 캐시 방식
- 웹 브라우저에서 캐시 - ex) 크롬에서 네이버 화면에 쓰일 데이터를 가져온다. 사이트에 재접속할 때는 기존의 화면에서 바뀐 부분만을 데이터를 가져오므로 로딩이 빠르다.
- 서버에서 캐시
- Client: 모바일 앱, 웹
- 한번 들어갔던 사이트 정보를 컨트롤러에서 저장해뒀다가 재접속하는 경우에 복사해둔 내용을 보여준다.
- 속도도 빨라지고 서버의 부하도 줄어든다.
- 캐싱할 때 유의사항
- 요청한 것에 대해 응답이 변하지 않는 경우에만 사용 가능하다.
- 캐시 적용 전
- openweathermap에서 데이터 받아오기 => Json 파싱 => DB에 저장
- 캐시 적용 후
- openweathermap까지 들어갈 필요가 없어진다.
- 미리 저장해둔 정보를 DB에서 가져오면 끝이다.
- 매일 정해진 시간마다 날씨 정보를 저장할 수 있도록 스프링 스케줄러 이용한다.
매일 정해진 시간에 데이터를 얻어오는 방법
- @Scheduled(cron = "0 0 1 * * *")를 메서드에 붙여주면 그 함수에 스케줄을 정해서 반복적으로 메서드를 수행한다.
- cron이라는 명령어는 특정 시간마다 작업을 수행하도록 한다.
- 매일 새벽 1시에 메서드가 실행된다.
- cron("초 분 시 일 월 dayOfTheWeek")
- 초: 0 ~ 59
- 분: 0 ~ 59
- 시: 0 ~ 23
- 일: 1 ~ 31
- 월: 1 ~ 12
- day of the week(0 - 7) (or MON -SUN -- 0 or 7 is Sunday)
- ex)
- 0 0 * * * *: 매 시각
- */10 * * * * * : 10초 마다
- 0 0 8-10 * * *: 매일 8시, 9시, 10시 마다
- ex)
7.2 Spring Scheduler
Ex) 날씨 저장 스케줄링
- Spring Boot에서 제공하는 스케줄링 기능 + 현재 날씨 조회 API(현재 날씨 조회는 무료) => 무료로 날씨 데이터를 저장하고 활용할 수 있다.
- date_weather 테이블을 만든다.
- 왜 또 테이블을 만들까?
- 사용자가 다이어리를 작성하면서 Diary 테이블을 수정한다.
- 서버에서는 이와 무관하게 하루 한 번 그 날의 날씨를 저장하기 위한 용도로만 쓰기 위해서 테이블이 필요하다.
<hide/>
create table date_weather(
date DATE not null primary key,
weather VARCHAR() NOT NULL,
icon VARCHAR() NOT NULL,
temperature DOUBLE NOT NULL );
- WeatherApplication에 @EnableScheduring 을 붙인다. 그럼 이 클래스 안에서 스케줄링 기능을 사용할 수 있도록 한다.
- dateWeather라는 엔티티를 만든다.
<hide/>
package zerobase.weather.domain;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.time.LocalDate;
@Data
@Entity(name = "date_weather")
@NoArgsConstructor
public class DateWeather {
@Id
private LocalDate id;
private String weather;
private String icon;
private double temperature;
}
- 위에서 만든 엔티티를 사용하기 위해 repository를 만든다.
- DiaryWeatherRepository
<hide/>
package zerobase.weather.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import zerobase.weather.domain.DateWeather;
import java.time.LocalDate;
@Repository
public interface DiaryWeatherRepository extends JpaRepository<DateWeather, LocalDate> {
}
- Service에 saveWeatherDate() 만든다. 매시간마다 날씨 데이터를 저장하는 역할
- 날씨 데이터 가져오는 함수 getWeatherFromApi()
- 날씨는 이제 하루 한 번만 가져온다.
<hide/>
private DateWeather getWeatherFromApi(){
// openweathermap에서 날씨 데이터 가져오기
String weatherData = getWeatherString();
// 받아온 날씨 json 파싱
Map<String, Object> parsedWeather = parseWeather(weatherData);
// 파싱된 날짜 데이터를 엔티티에 넣어준다.
DateWeather dateWeather = new DateWeather();
dateWeather.setDate(LocalDate.now()); // 날씨를 가져오는 시점의 데이터를 넣어준다.
dateWeather.setWeather(parsedWeather.get("main").toString());
dateWeather.setIcon(parsedWeather.get("icon").toString());
dateWeather.setTemperature((Double) parsedWeather.get("temp"));
return dateWeather;
}
- 이제 getWeatherFromApi()를 이용해서 saveWeatherDate()에 활용한다.
- saveWeatherDate()도 결국 DB를 사용하는 함수이다.
- @Transactional을 붙인다. 하나의 트랜잭션으로서 동작하도록 설정
- saveWeatherDate()도 결국 DB를 사용하는 함수이다.
<hide/>
@Transactional
@Scheduled(cron = "0/5 * * * * *") //5초 마다 동작
public void saveWeatherDate(){
dateWeatherRepository.save(getWeatherFromApi());
}
- 데이터베이스에 5초에 한 번씩 INSERT 되고 있지만 @Id는 LocalDate 타입이므로 row가 하나만 나오는 상태로 업데이트 된다. 따라서, 하루에 한 개씩 row가 생길 예정이다.
- 스프링 부트에도 5초에 한 번씩 insert되는 걸 확인 가능하다.
- 리포지토리 메서드
List<DateWeather> findAllByDate(LocalDate localDate);
- createDiary()를 수정한다.
- 이제는 날씨를 매일 저장해두기 때문에 매번 API를 호출할 필요가 없어진다.
- 기존의 코드 두 줄을 제거한다.
- DB에서 날씨 정보를 가져오도록 수정한다.
- 날씨 정보를 가져오는 메서드 getDateWeather()를 추가한다.
<hide/>
private DateWeather getDateWeather(LocalDate date){
List<DateWeather> dateWeatherListFromDB = dateWeatherRepository.findAllByDate(date);
// DB에 정보가 없는 경우
if(dateWeatherListFromDB.size() == 0){
return getWeatherFromApi();
}
return dateWeatherListFromDB.get(0);
}
- 다이어리 클래스에 메서드 setDateWeather(DateWeather) 만든다.
- DateWeather를 가져와서 다이어리에 넣어준다.
<hide/>
public void setDateWeather(DateWeather dateWeather){
this.date = dateWeather.getDate();
this.weather = dateWeather.getWeather();
this.icon = dateWeather.getIcon();
this.temperature = dateWeather.getTemperature();
}
- createDiary()
- 기존과 다르게 매일 파싱하지 않아도 된다.
- 매일 API에서 정해진 시간에 날씨 데이터를 저장해둠으로써 나중에 과거 날씨를 무료로 가져올 수 있도록 한다.
<hide/>
@Transactional(isolation = Isolation.SERIALIZABLE)
public void createDiary(LocalDate date, String text){
// 날씨 데이터 가져오기
DateWeather dateWeather = getDateWeather(date);
// 파싱된 데이터와 일기 값을 내 데이터베이스에 넣기
Diary nowDiary = new Diary();
nowDiary.setDateWeather(dateWeather);
nowDiary.setText(text);
diaryRepository.save(nowDiary); // DB에 데이터 넣는다.
}
출처 - 제로베이스 백엔드 스쿨 (김조현 강사님)
'Spring Projcect > 날씨 일기 프로젝트' 카테고리의 다른 글
Chanpter 09. 예외 처리하기 (0) | 2022.09.01 |
---|---|
Chapter 08. 로그(log) 남기기 (0) | 2022.09.01 |
Chapter 06. Spring Transaction(스프링 트랜잭션) (0) | 2022.08.31 |
Chapter 05. 날씨 데이터 CRUD (0) | 2022.08.31 |
Chapter 04. 날씨 데이터 저장하기 (0) | 2022.08.31 |