0211 - 0220
# 0211 - 0220
# 0213 - 쿼리 캐시
- 쿼리 캐시란, SELECT 쿼리문을 이용하여 조회한 값을 저장하고 있다가, 같은 쿼리 문을 요청하였을 때 미리 캐싱된 값을 반환하는 DBMS 기능이다
- 일반적인 웹사이트와 같이 쓰기 (WRITE)보다, 읽는(READ) 횟수가 많은 환경에서 유용하다
- 하지만, 멀티 코어 시스템 및 처리량이 높은 환경에서는 확장성이 좋지 않으므로 기본적으로 사용되지 않도록 설정된다
# 쿼리캐시 기능 사용하기
- 쿼리 캐시 기능을 사용할 수 있는지 확인하려면, 기본적으로 have_query_cache 설정이 되어 있어야 한다
SHOW VARIABLES LIKE 'HAVE_QUERY_CACHE'
- 조회 결과 yes로 나온다면, 쿼리 캐시 기능을 사용할 수 있다는 뜻이다.
SHOW VARIABLES LIKE 'QUERY_CACHE_TYPE'
- 그 다음에는 현재 시스템에서 쿼리 캐시 기능을 사용하고 있는지를 확인할 수 있다.
# 쿼리캐시가 되지 않는 경우
아래와 같은 함수를 사용하면, 기본적으로 쿼리가 캐싱되지 않는다.
BENCHMARK()
CONNECTION_ID()
CONVERT_TZ()
CURDATE()
CURRENT_DATE()
CURRENT_TIME()
CURRENT_TIMESTAMP()
CURTIME()
DATABASE()
ENCRYPT() (one parameter)
FOUND_ROWS()
GET_LOCK()
LAST_INSERT_ID()
LOAD_FILE()
MASTER_POS_WAIT()
NOW()
RAND()
RELEASE_LOCK()
SLEEP()
SYSDATE()
UNIX_TIMESTAMP()
(no parameters)
USER()
UUID()
UUID_SHORT()
- 또한 쿼리에 아래와 같은 구문이 있을 경우 쿼리가 캐싱되지 않는다.
SELECT SQL_NO_CACHE ...
SELECT ... INTO OUTFILE ...
SELECT ... INTO DUMPFILE ...
SELECT ... FOR UPDATE
SELECT * FROM ... WHERE autoincrement_column IS NULL
SELECT ... LOCK IN SHARE MODE
# 쿼리캐시 크기를 제한하기
SHOW VARIABLES LIKE 'query_cache_size';
SET GLOBAL query_cache size = 80000000;
- 쿼리 캐시 크기 설정
# 캐시 설정 및 의미
SHOW STATUS LIKE 'Qcache%';
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1158 |
| Qcache_free_memory | 3760784 |
| Qcache_hits | 31943398 |
| Qcache_inserts | 42998029 |
| Qcache_lowmem_prunes | 34695322 |
| Qcache_not_cached | 652482 |
| Qcache_queries_in_cache | 4628 |
| Qcache_total_blocks | 11123 |
+-------------------------+----------+
- Qcache_inserts는 현재, 캐싱된 쿼리의 값을 의미한다.
- Qcache_hits는 쿼리를 캐싱하여, 캐싱된 값을 반환한 값을 의미한다
- Qcache_lowmem_prunes는 메모리 값이 부족하여, 캐시에서 이전에 있던 값을 제거한 값이다
- Qcache_lowmem_prunes 값을 줄이려면 앞서 말했던, query_cache_limit 값을 적절히 설정해줘야한다.
# 결론
- 그 밖에도, query_cache_wlock_invalidate 옵션을 끄면, WRITE락이 걸려있더라도 캐싱된 값을 반환하게 하여, 경합 상태에서도 기다리지 않고 값을 읽을 수 있다
- 캐시된 쿼리를 잘 이용하면, 성능을 높일 수 있다
- 실제 SQL문은 대소문자를 구분하지 않지만, 캐싱된 쿼리 값을 반환받기 위해서는 대소문자까지 같아야 하므로, 팀 내에서 쿼리문을 통일성 있게 작성하는 노력을 해야할 것이다. 그 밖에도 동일한 쿼리라는 것을 인식하려면 여러 값들이 일정해야한다
- 쿼리 캐시 값의 크기를 크게 늘리면, 읽기 속도는 빨라지겠지만, 락 경합 때문에 쓰기 속도는 느려질 수 있다. 최적값을 찾아 적용해야 한다.
# 0214 - Jackson 상세 정리
# Jackson과 기존 GSON or SimpleJSON의 차이
결론 적으로 차이는 없다. Jackson도 ObjectMapper API를 사용하여, 여타 GSON Ehsms SimpleJSON과 같이 객체에 데이터를 세팅해줘야 한다. 특별한 점은 Spring 프레임워크와 Jackson의 관계에서의 장점이 있다. Spring 3.0 이후부터, Jackson과 관련된 API를 제공함으로써, Jackson 라이브러리를 사용할때, 자동화 처리가 가능하게 되었다.
# Jackson 동작
Spring 3.0 이후로 컨트롤러의 리턴 방식이 @ResponseBody 형식이라면, Spring은 MessageConverter API를 통해, 컨트롤러가 리턴하는 객체를 후킹 할 수 있다.
Jackson은 JSON 데이터를 출력하기 위한 MappingJacksonHttpMessageConverter를 제공한다. 만약 우리가 스프링 MessageConverter를 MappingJacksonHttpMessageConverter으로 등록한다면, 컨트롤러가 리턴하는 객체를 다디 뜯어(자바 리플렉션 사용), Jackson의 ObjectMapper API로 JSON객체를 만들고 난 후, 출력하여 JSON 데이터를 완성한다. 나아가 Spring 3.1 이후로 classpath에 Jackson라이브러리가 존재한다면 자동적으로 MessageConverter가 등록된다
@RequestMapping("/json")
@ResponseBody
public Object printJSON() {
Person person = new Person("Person", "Developer");
return person;
}
# Jackson 특징
- Jackson은 기본적으로 프로퍼티로 동작한다
- Java는 프로퍼티를 제공하는 문법이 없으므로 Getter와 Setter를 기준으로 작동한다(멤버변수의 유무가 아닌)
# Jackson의 데이터 매핑을 Getter가 아닌 멤버변수 변경
- Jackson은 @JsonProperty API를 통해 변경이 가능하다
public class Person {
@JsonProperty("name")
private String myName = "Person";
}
# Jackson의 데이터 매핑 법칙 변경하기
매번 멤버변수로 변경하기 위해 @JsonProperty를 선언하는 방버이 아닌 데이터 매핑 법칙을 변경할 수 있다
- @JsonAutoDetect API를 통해 변경
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class Person {
private String myName = "Person";
}
- @JsonAutoDetect는 멤버변수 뿐만 아니라, Getter, Setter의 데이터 매핑 정책도 정할 수 있다.
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class Person {
private String myName = "Person";
public String getJob() {
return "Developer";
}
}
- Getter를 제외하고 싶다면, @JsonIgnore API를 사용 할 수 있다.
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class Person {
private String myName = "Person";
@JsonIgnore
public String getJob() {
return "Developer";
}
}
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NON_PRIVATE)
public class Person {
private String myName = "Person";
public String getJob() {
return "Developer";
}
}
- Getter 정책으로 private만 바인딩에 제외 할 수 있다.
# Jackson의 데이터 상태에 따른 포함 관계 설정
- 만약 Jackson 데이터 매핑시 NULL 값과 같은 특정 데이터 상태인 경우를 제외하고 싶을 땐 @JsonInclude API를 사용한다
- NULL을 클래스 전반적으로 제외하고 싶다면, 클래스 위에 선언한다
- 특정 프로퍼티에 적용하고 싶다면 프로퍼티 위에 선언한다
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Person {
private String myName = "Person";
public String getJob() {
return "Developer";
}
}
public class Person {
private String myName = "Person";
@JsonInclude(JsonInclude.Include.NON_NULL)
public String getJob() {
return "Developer";
}
}
- JsonInclude.Include 속성은 NON_NULL 뿐만 아니라 몇몇 개가 더 존재한다.
# 0215 - @JsonProperty, @JsonNaming
- JSON데이터를 주고 받을때 CamelCase <-> snake_case 변경하기 위해 사용
- @JsonProperty
public class JsonData1 {
@JsonProperty("json_data1")
private String jsonData1;
@JsonProperty("json_data2")
private String jsonData2;
}
// {"json_data1":"123","json_data2":"456"}
- @JsonNaming
@JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class)
public class JsonData2 {
private String jsonData1;
private String jsonData2;
}
// {"json_data1":"가나다","json_data2":"마바사"}