목록공부 (77)
빠에야는 개발중
OSIV 무엇인가? OSIV란 Open Session In View의 약자로 JPA에서 영속성 컨텍스트와 hibernate session을 뷰가 렌더링 될 때까지 유지시키는 방법이다. 왜 사용하는가? 기존에 @Transactional 메소드까지 유지가 되던 영속성 컨텍스트의 영향 범위는 뷰 렌더링까지는 닿지 않는다. 따라서 controller 단에서 엔티티를 조회할 때 Lazy loading이 걸린다면, LazyInitializationException을 뱉으면서 실패한다. 이를 해결하기 위해서 영속성 컨텍스트가 뷰를 그릴때도 유지될 수 있도록 하여 Lazy loading을 성공시키는 것이다. 단점 전통적인 OSIV를 기준으로 요청이 들어왔을 때 controller단에서 부터 JDBC connection..
N+1 문제 무엇인가? N+1 문제는 JPA에서 하나의 부모 객체와 다수의 자식 객체 데이터를 얻기 위해 메소드를 호출했을때 부모를 조회하는 쿼리 1개와 하위의 N개의 자식들을 조회하는 쿼리 N개가 발생하는 문제이다. 이는 1:N 관계에서 fetch type이 eager loading일 때 findAll() 따위로 전체를 조회하는 메소드를 사용하거나, lazy loading일 때 자식 객체를 반복문 따위로 순환 조회하는 과정에서 발생한다. 한번의 쿼리로 join해서 가져올 것을 자식 객체 수만큼의 쿼리를 사용하니 당연히 성능적으로 좋지 않다. 어떻게 해결하는가? JPQL에서는 fetch join이라는 기능을 제공한다. 데이터를 한번에 가져올 수 있도록 해준다. 하지만 두 개 이상의 컬렉션을 가진 엔티티를..
무엇인가? CAS(Compare And Swap)은 동시성 처리를 위한 세가지 방법(volatile, synchronized, CAS) 중 하나로서 말 그대로 “비교한 후 바꿔주는 것”이다. 멀티 스레드, 멀티 코어 환경에서 각 변수는 스레드 내의 스택(캐시)에 저장된다. 이 변수에 대해서 스레드에 저장된 값과 메인 메모리에 저장된 값을 비교하여 값이 같다면 새로운 값으로 치환해준다. 값이 다르다면 계속 재시도를 한다. CAS는 lock을 걸지 않고 변수마다 동기화를 하기 때문에 값이 싸다. 물론 volatile 키워드도 변수마다 동기화를 해줄 수 있지만 읽기 연산에서만 사용할 수 있다는 단점이 있다. 실제로 CAS의 내부 구현에서 메인 메모리의 값을 가져오는 용도로 volatile을 사용한다. 어디에 ..
무엇인가? @Transactional 어노테이션은 스프링에서 제공하는 클래스, 메소드 레벨의 트랜잭션 지원 어노테이션이다. 이 어노테이션이 선언되면 스프링은 프록시 객체를 생성하여 자동 commit, rollback 등의 트랜잭션 처리를 맡긴다. 클래스, 메소드 내에서 Persistence layer에 접근하여 데이터를 조작, 조회 할 때 사용한다. 주로 Service layer에서 사용하게된다. 트랜잭션 격리 수준 트랜잭션 어노테이션답게 트랜잭션의 기능들 중 하나인 격리 수준 속성을 가지고 있다. Default 기본 격리 수준(DB의 격리 수준을 따름) READ_UNCOMMITTED (Level 0) 커밋되지 않은 데이터 읽기 허용 변경 중인 데이터에 접근할 수 있다. Dirty read 문제가 발생할..
배열을 오름차순으로 정렬하고 k만큼의 간격으로 최대, 최소값 쌍을 만들어 순회한다. 가장 작은 값을 골라낸다. 기존 배열을 변경하지 않고 그냥 순회를 해서 회전까지 생각을 한다면 부분 배열 골라내기 + 부분 배열에서 최소값 찾기를 해야하기 때문에 오랜 시간이 걸릴 것이다. 게다가 중복 연산도 있을 수 있다. 하지만 정렬을 하면 O(nlogn) 시간에 끝날 수 있기 때문에 빠르다.
생각했던 것 내림차순으로 각 요소를 정렬해서 사람 수만큼 하나씩 쭉 빼주다가 마지막 사람에게 전부 몰아주는 방법을 생각했다. 하지만 예제를 보면서 틀렸다는 걸 알았다. 맨 마지막에 남은 값들을 다 몰아주면 결과값이 선형적으로 증가할 것이기 때문이다. 그래서 수정한 방법은 꽃의 개수를 균일하게 가져갈 수 있도록 분배하는 것이었다. 꽃의 가격에 영향을 주는 것은 이전, 이후의 꽃의 가격이 아닌 "해당 꽃을 사는 사람의 이전 구매 개수"이다. 따라서 개수를 잘 조절하면 최소값을 얻을 수 있다. 진행 해시맵에 사람 수만큼의 원소를 넣고 내림차순 정렬한 꽃 배열을 순회하면서 순차적으로 해시맵의 구매 개수를 늘려준다. 개수를 매번 더해주면서 꽃의 가격도 함께 계산해준다. 여담 역시나 정렬을 기본으로 생각하니 생각하..
생각했던 것 important contest와 not important contest를 구분해서 저장해주면 연산하기가 훨씬 쉽다. 한꺼번에 넣어주면 다중 조건 정렬을 해줘야하기 때문이다. 진행 luck을 key라고 하고, 중요성을 value라고 두었을 때 value가 1인 것들을 따로 담아서 내림차순 한 다음, 받은 개수만큼은 앞에서부터 순차적으로 남겨두고 나머지 뒷부분은 전부 같은 절대값의 음수로 바꿔준다. 그리고 모든 리스트들의 값들을 더해주면 결과값이 나온다. 여담 그리디 알고리즘은 대부분 정렬로부터 시작되는 것 같다. 정렬을 내가 직접 구현하지 않아도 돼서 편하게 문제를 풀 수 있어 다행이다.
생각했던 것 절대값들 중 최소값을 찾는 문제로, 모든 경우의 수를 비교하여 최소값을 찾아내면 된다. 진행 ... 라고 하였으나 그러면 0(n^2) 시간에 끝날 것이기 때문에 비효율적이다. 경우의 수를 줄이기 위해서 생각한 것은 "정렬"이다. 예를 들어 오름차순으로 정렬했을때 [A, B, C] 배열이 도출되었다면 (A, B)의 차이는 (A, C)의 차이보다 작을 수 밖에 없다. 그러므로 모든 경우의 수를 따지지 않고, 바로 옆의 수와 비교하기만 하면 된다. 그러면 정렬하는 시간 O(nlogn) + 탐색시간 O(n)으로 O(nlogn) 시간 안에 끝낼 수 있다. 여담 각 수가 양수, 음수 여부에 따라 절대값 계산이 다를거라고 잠깐 착각했었다.. 그냥 뒷수에서 앞 수를 빼면 된다.
생각했던 것 척봐도 LCS(Longest Common Sequence, Substring이 아니다.) 문제임을 알 수 있었다. 부분 수열이 무엇인지는 필요없고 개수만 파악하면 돼서 오히려 더 쉬운 문제였다. 진행 일반적인 LCS 풀이와 같이 했다. 0부터 시작하는 테이블을 만들어 두 문자열을 비교해가면서 두 문자가 같은 경우는 직전 문자열(테이블의 대각선 1칸 전의 값)까지의 개수 + 1을 해주고, 다른 경우에는 각 문자열의 직전 문자열(테이블의 아래, 위로 1칸 전의 값 중 최대값)까지의 개수를 가져오면 된다. 예컨대, 두 문자가 같은 경우 ABCD와 ACCB에서 세번째 C가 같기 때문에 AB, AC의 최장 수열 개수인 1(A만 공통)에서 1을 더해줘 2가 된다. 두문자가 다른 경우 ABCD와 ACCB..
에피소드 어쩌다보니 회사에서 기존에 운영하고 있던 데모 시스템의 UI를 수정하게 됐는데, React.js를 사용한 WEB UI였다. 로컬 테스트를 위해서 클라이언트와 서버(golang으로 작성되어 있음)를 띄웠고 로그인을 시도했는데, CORS 경고가 떴다. 그래서 실제로 동작하고 있는 클라우드 서버의 네트워크 로그를 보며 공부해보았다. CORS란? CORS란 Cross Origin Resource Sharing의 약자로 브라우저의 현재 웹페이지가 이 페이지를 받은 서버가 아닌 다른 서버의 자원을 호출하는 것을 의미한다. 이것을 허용하면 악의적인 도메인으로의 요청을 무조건 허용하게 되어 보안 문제가 발생할 수 있다. 그래서 HTTP 스펙에서 이에 대한 기준을 제시하고 있다. 나는 CORS를 ip만 같으면 ..