1. 서론

 

 CORS 문제는 Web 관련 개발을 하다 보면 Framework 와 무관하게 한번 쯤 맞이 할만한 문제이다. 본 글에서는 GLOBAL 하게 CORS 설정을 하는 법에 대해 공유하고자 한다. 

 

 

2. 본론

 

2-(1) WebMvcConfigurer 구현

 

- 설명

 

 SpringBoot 는 SpringMVC 를 비롯해 웹 개발에 필요한 여러 라이브러리들을 개발자에게 제공해주는 일종의 보따리 이다. 때문에, SpringBoot 를 통해 CORS 를 설정하고자 할 때는 Spring MVC 의 CORS 를 설정하는 것처럼 Web MVC 하위에 있는 WebMvcConfigurer 를 implements 후 설정해주면 된다.

 

- 예시

 

 

 

- 참고

 

  Spring Docs 에서는 이 방법을 추천하고 있다. 

 

 

2-(2) CORS 필터 Bean 등록

 

 - 설명 

 

본 방법은 title 그대로 CORS 필터를 구현 후 Bean 으로 등록하는 것이다. 본 방법의 경우, Spring MVC 가 아닌 Spring Web 에만 의존하고 있거나 security 설정 level 에서 CORS 를 필수적으로 체킹해야 되는 경우 유용하다고 할 수 있겠다.

 

- 예시

 

 

- 참고 

 

본 설정에서 가장 중요한 것은 Component 의 order 순서이다. 



3. 결론

본 글에서 Global 하게 CORS 를 설정하는 2가지 방법에 대해 소개했다. 본 방법들이 아닌 XML 을 통해 Global 하게 설정하는 방법도 존재한다. 다만, 실무에서 XML 을 통해 여러 설정들을 하는 것들보다는 Code 레벨에서 관리하는 것이 유지보수 측면에서 편리하다는 것이 필자 개인의 생각이며 성향이다. XML 을 통해 Global 하게 설정하는 방법 혹은 Controller 단에서 CORS 를 제어하는 방법들도 존재하니 이 부분들이 궁금한 독자들은 아래의 참고 링크를 통해 Spring Docs 를 읽어보는 것을 추천한다.



4. 참고

 

- Spring Docs - CORS 설정 방법 소개

https://spring.io/blog/2015/06/08/cors-support-in-spring-framework

 

- WebMvcConfigurer

https://bit.ly/3fYzcNs

 

- CorsFilter

https://bit.ly/3yWVKar

[ Node 설치 하기 ]

 

1. 설치 가능한 node 버전 조회 및 설치 
- nvm ls-remote 

- nvm install (버전명)

 

2. local 에 설치된 node 확인 

- nvm list 

 

3. 기본으로 사용할 node 버전 지정

- nvm alias default (버전명) 

 

 

[ 참고 ]

- 회사 혹은 운영 상의 목적으로 Node 를 사용할 경우, 짝수 버전을 사용할 것 ( nodejs.org/en/about/releases/ )

 

1. 서론

 

 MySQL, MariaDB 의 default Isolation level 은 REPEATABLE READ 이다. 그런데, RDB 하면 떠오를 만한 대표적인 DB 인 Oracle, Postgresql 은 READ COMMITTED 수준의 default Isolation level 를 갖고 있다. 문득 Isolation level에 따른 차이가 무엇이 있을지 궁금하게 되었고 이를 바탕으로 각 Isolation level에 대해 정리해놔야 겠다는 생각이 들어서 본 글을 끄적이게 되었다. 참고로 본 글에서 테스트 시 사용한 RDB는MariaDB 이며, engine 은 row level lock 을 지원해주는 InnoDB 를 사용했다.  

 

 

2. 본론

 

- 테스트 시 사용한 TABLE 

user(사용자) table
account(계좌) table

 

 

2-(1) READ UNCOMMITTED

 

  - 설명

 

 A User 가 transaction 을 시작하고 특정 값을 update 했으며 아직 commit 을 하지 않았다고 생각해보자(②). READ UNCOMMITTED 의 경우 B User 가 해당 값을 select 했을 경우 A user 가 commit 을 하지 않았음에도 B user 의 select 시에는 A User 가 update 한 내용이 보인다.(③) 이를 통상적으로 dirty read 현상이 일어 났다고 일컫는다. 뿐만 아니라, READ UNCOMMITTED 는 Non-repeatable read 와 Phantom read 현상도 발생한다. 이 양자의 현상에 대한 설명은 글의 마지막에 기술하겠다. 

 

- 잘 사용하지 않는 이유 

 

 dirty read 현상은 B user 에게 확정되지 않은 data 를 제공해줌으로 인해 B user 가 현재 본인이 조회한 data 로 특정 판단을 내린 경우, 해당 판단의 전제가 되는 data 가 변동 될 수 있다는 점에서 큰 단점이 있다. 

 

 

- 테스트 내용 

 

  ① Isolation level 설정

 Isolation level

 

  ② (A user 화면) A user 가 transaction 을 시작하고, 특정 data 를 update 함. 아직 commit 을 하지 않음.

A user

 

③ (B user 화면) A User 가 commit 을 하지 않았음에도 B User 에게는 update 된 값이 보인다.

B user

 

트랜젝션은 하나의 논리 로직을 구성한 단위를 의미한다. 때문에, 하나의 트랜잭션의 과정 자체를 다른 User 에게 노출시키고 이를 바탕으로 다른 User 에게 정확하지 않을 수도 있는 Data 를 제공하는 것은 트랜젝션의 취지에 맞지 않는다고 생각한다. 필자는 개인적으로 이와 같은 이유로 인해 본 level 의 격리 수준을 사용하지 않는다. 

 

 

2-(2) READ COMMITTED

 

 - 설명 

 

2-(1) 의 경우 A user 가 commit 을 하지 않았음에도 B user 에게 A user 가 수정한 data 가 노출되었다. READ COMMITTED 는 A user 의  트랜잭션에서 COMMIT 된 데이터만 B user 가 읽어올 수 있는 level 이다. REPEATABLE READ 과 더불어 가장 보편적으로 사용되는 격리 수준이다. 이 경우에 Dirty read 는 발생하지 않지만 Non-repeatable read 와 Phantom read 현상은 지속적으로 발생한다. 

 

- 사용처

 

 Oracle 과 PostgreSQL 의 경우 본 level 을 default 격리 수준으로 사용하고 있다. 

 

- 테스트 

  ① Isolation level 설정

 Isolation level

  ② (A user 화면) A user 가 transaction 을 시작하고, 특정 data 를 update 함. 아직 commit 을 하지 않음.

A user 가 특정 data 를 update 하고 select 한 화면 ( commit x )

 

 

③ (B user 화면) A User 가 commit 을 하지 않았기 때문에 B User 에게는  최초의 값이 보인다. 즉, commit 된 값만 B user 에게 노출된다. 만약, ② 에서 A user 가 commit 을 진행했다면, 본 화면에서 amount 는 4000 으로 보일 것이다. 

B user 화면 

 

 

2-(3) REPEATABLE READ

 

 - 설명 

 

 위에서 격리 수준들에서 생기던 문제인 dirty read, Non-repeatable read, Phantom read현상이 모두 일어나지 않는다. 다시 말해, 하나의 트랜젝션에서 항상 동일한 select에 대한 동일한 결과를 보장하는 것을 의미한다.

 

 - 사용처

 

 MySQL 과 MariaDB 의 경우 본 level 을 default 격리 수준으로 사용하고 있다.

 

 

 - 테스트

 

  ① Isolation level 설정

 Isolation level

  ② (A user 화면) A user 가 transaction 을 시작하고, 특정 data 를 insert 하고 commit 까지 진행

A user 가 특정 data 를 insert 하고 commit 까지 진행

 

 ③ (B user 화면)  ② 의 현상이 일어나기 전에 transaction 을 시작하고,  ②의 현상이 일어난 후에 select 문을 실행. ②에서 진행한 insert문에 대한 결과가 반영되지 않았음을 알 수 있다. 이를 통해 하나의 transaction 에서는 항상 같은 select에 대해 같은 결과의 값이 나오는 것을 알 수 있다.

 

 

2-(4) SERIALIZE

 

 - 설명  

 

shared lock 을 통해 select 문에 조회 되는 row 들에 대해 lock 을 설정하는 격리 수준이다. 

 

- 잘 사용하지 않는 이유 

 

select 에 걸린 모든 row 에 shared lock 을 걸어버린다면 사용자가 많아지는 경우, 동시 작업에 대해 지속적인 lock 현상으로 인해 부하가 발생할 수 있다. 

 

- 테스트

 

  ① Isolation level 설정

 

  ② (A user 화면) A user 가 transaction 을 시작하고, select 문을 실행. SERIALIZE level 에서는 단순 select 문을 실행해도 모든 select 문에 자동적으로 sql 문 마지막에 "...for share" 이 붙는다고 생각하면 된다. 

A user 의 화면 

 

 

③ (B user 화면) ② 에서 A user 가 select 문을 shared lock 을 통해 실행했기 때문에, 특정 data 를 update 하려고 할 경우 ② 의 lock 이 풀리기 전까지는 불가능하다. 

lock 

 

 

3. 결론

 

 위의 내용들을 정리하면서 READ UNCOMMITTED 와 REPEATABLE READ의 격리 수준이 가장 많이 사용되는 이유를 나름 알 수 있었다.그렇다면, 도대체 READ UNCOMMITTED 와 REPEATABLE READ 은 어떻게 A user 와 B user 에게 상황에 맞게 다른 data 들을 보여주고 특정 User 가 해당 트랜잭션을 취소하면 rollback 을 통해 예전 버전의 data 로 돌아갈 수 있을까라는 의문이 든다. 이는 snapshot 과 MVCC 패턴을 이용해서 가능한 것이다. 이에 대해서는 다음 글에서 다루도록 하겠다.

 

 

4. 참고

- Non-repeatable read 현상

 

: 하나의 transaction 내에서 동일한 select 문에 대한 결과가 다른 현상을 말한다.

 

- Phantom read 현상

 

:  insert 문으로 인해 Non-repeatable read 현상이 발생한 것을 말한다. 다시 말해, A user 의 update 로 인한 data 변화(commit 까지 진행한 data)가 B user 의 select 문에는 반영되지 않지만, A user 의 insert 로 인한 data 변화는  B user 의 select 문에 반영되는 현상을 의미한다. 

 

 

- PostgreSQL 의 default 격리 수준 

https://www.postgresql.org/docs/9.5/transaction-iso.html

 

PostgreSQL: Documentation: 9.5: Transaction Isolation

The SQL standard defines four levels of transaction isolation. The most strict is Serializable, which is defined by the standard in a paragraph which says that any concurrent execution of a set of Serializable transactions is guaranteed to produce the same

www.postgresql.org

- Oracle 의 default 격리 수준 

https://blogs.oracle.com/oraclemagazine/on-transaction-isolation-levels

 

On Transaction Isolation Levels

Our technologist isolates transactions safely.

blogs.oracle.com

- Shared lock 이란

https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html

 

MySQL :: MySQL 8.0 Reference Manual :: 15.7.2.4 Locking Reads

If you query data and then insert or update related data within the same transaction, the regular SELECT statement does not give enough protection. Other transactions can update or delete the same rows you just queried. InnoDB supports two types of locking

dev.mysql.com

 

'DB > RDB' 카테고리의 다른 글

MariaDB 최초 비밀번호 설정 시 주의점  (0) 2020.04.15

1. 문제의 발견

 

  Ubuntu 18.04 LTS 를 기준으로 소스 설치를 하지 않는 이상 대게 apt install mariadb-server 명령어를 통해 MariaDB 를 설치한다. 그 후, mysql_secure_installation 명령어를 통해 최초 기본 설정을 진행하게 되는데 그 설정 가운데 root password 를 설정할 수 있는 step 이 존재한다.  필자는 해당 step 에서 설정한 비밀번호를 바탕으로 MariaDB 접속을 시도했는데, 비밀번호가 없이도 접속이 가능했다. 즉, password 설정이 제대로 안된 것이다.

 

2. 원인

 

 그 이유는 다음과 같다. MariaDB 10.4.3 버전 이상부터는 local Unix socket file 을 통해 MariaDB 를 접근하려고 하는 것이 default 로 설정이되어 있는데, 이 때는 운영 체제 자체의 "증명" 을 따른다는 것이다. 쉽게 이야기 하자면, OS 자체의 비밀번호 설정을 따른다는 것인데 이렇게 되면 최초 기본 설정 시에 (mysql_secure_installation) 설정했던, MariaDB root password 설정이 제대로 작동하지 않는다. 

 

3. 해결방안 

 

 해당 부분을 disable 시키고 MariaDB 자체에 설정해놓은 root password 를 실제 MariaDB 접속 시에 사용하고자 한다면, MariaDB 의 mysql database > user table 에서 다음과 같은 명령어를 사용하면 된다. [ UPDATE user SET plugin=""; ] 
그 후에, MariaDB root password를 재설정한다면 재설정한 password를 바탕으로 접속이 가능할 것이다. 

 

4. 참고

 

https://mariadb.com/kb/en/authentication-plugin-unix-socket/

 

Authentication Plugin - Unix Socket

Uses the user name that owns the process connected to MariaDB's unix socket file.

mariadb.com

https://mariadb.com/kb/en/after-reset-root-password-i-still-get-access-denied-for-user-rootlocalhost/

 

after reset root password I still get "Access denied for user 'root'@'localhost'"

I reset the root password of the mariadb server but when I then try to login, I still get Access denied for user 'root'@'localhost' To change the root password I did the follo...

mariadb.com

 

'DB > RDB' 카테고리의 다른 글

Isolation level 이란  (1) 2020.04.17

[ Introduction ]

mixin 은 Vue.js 에서 재사용 가능한 기능을 한 곳에 묶어 코드의 중복을 줄여주기 위해 등장한 방법입니다. 예컨대, 이메일 혹은 비밀번호 등의 정규식 Rule 을 mixin 이라는 개념으로 묶어 한 곳에서 관리하고, 해당 정규식이 필요한 View 에서 mixin 을 가져다가 (import) 쓸 수 있습니다. 그러나, Mixin 을 사용할 때 주의해야 할 점이 있습니다. Mixin 내부에서 API 를 호출하는 것은 지양하는 것이 좋다는 것 입니다. 그 이유를 아래에서 함께 살펴보도록 하겠습니다. 

[ Description ]

- 아래의 예제 및 설명은 모든 API 를 created 에서 호출한다고 가정하고 진행합니다.

 

[ 사전 지식 ]

- mixin 의 created() 는 view 의 created() 보다 항상 먼저 호출됩니다.

 

mixin file 내부

 

mixin 을 가져다 사용하려는 view 내부

 

mixin 의 created 가 view 의 created 보다 먼저 호출된 것을 알 수 있습니다

 

[ 문제의 제기 ]

 - mixin 의 created() 에서 api 를 호출했을 경우, 모든 Logic 을 마치기 전에 view 의 created() 가 호출 됩니다.

 

mixin file 내부 - created() 에서 API 를 호출하고 있다

 

mixin 을 가져다 사용하는 view 파일 내부 - created() 에서 API 를 호출하고 있다.

 

* 필자는 위의 로직을 처음 만들었을 때, console 에 mixin step 1 -> mixin step 2 -> mixin step 3 -> vue step 1 -> vue step 2 -> vue step 3 이 찍힐 것으로 기대했다. 그 이유는 [사전 지식]의 예시 처럼 mixin 의 created() 가 view 의 created() 보다 항상 먼저 호출 되기 때문이다. 그러나 예상과는 달리 결과는 아래와 같았다. 

 

엥... 순서가 왜이리 뒤죽박죽 이지...

 

* 위의 예시를 통해 알 수 있는건 mixin 의 created() 가 해당 mixin 파일을 호출한 view 의 created() 보다 항상 먼저 호출은 되지만 그렇다고 mixin 의 모든 로직이 항상 mixin 을 호출한 view 의 로직보다 선행된다는 것은 아니라는 것입니다. 요컨대, mixin 의 created() 에서 api 를 호출하고 그 응답 값을 해당 mixin 을 호출한 view 에서 사용하려는 것은 안전하지 않은 방법입니다.

 

 

[ 해결 방안 ]

- 위의 문제를 해결하려면 mixin 에서는 api 를 호출하는 함수를 정의만 하되 실제 해당 함수를 호출하는 것은 mixin 이 아닌 해당 mixin 을  호출한 view 에서 해야 한다. 필자는 위에 해당 방법의 예시로 아래 case 를 제시합니다.

 

mixin 에서 api 를 호출하는 mixinFunction 을 호출하지 않고, 해당 함수를 mixinFun 이라는 변수에 담아 정의했다.

 

mixin 에서 함수를 담고 있는 변수(data) 인 mixinFun 을 view 에서 호출했다  

 

그 결과는 위와 같다.

 

[ 참고 ]

- 예시에 사용 된 코드는 vue-cli (3.9.2 version) 로 생성한 프로젝트에 기반하고 있습니다.

 

https://github.com/GwangGeun/vueJs-blog-content/blob/master/src/views/Mixin.vue

 

 

'Front-End > Vue.js & Vuex' 카테고리의 다른 글

v-model 사용시 주의점 #1  (0) 2020.01.26
v-model 사용시 주의점 #2  (0) 2020.01.19

[ Introduction ]

 v-model 은 form element 에 "data 의 양방향 바인딩" 을 가능하게 해주는 지시문 입니다. 그러나, v-model 을 사용하다보면 v-model 에 binding 되어 있는 value 값이 종종 user 가 입력한 값 그대로 반영되지 않고 일부분만 반영되거나 예상치 못한 값이 들어가있는 것을 확인 할 수 있습니다. 그 이유는 "한글" 은 "중국어" 와 "일본어" 등과 같이 IME 가 필요한 언어이기 때문입니다. 이를 해결하기 위해서 공식문서는 input event 와 "data의 단방햔 바인딩" 을 가능하게 해주는 v-bind 를 사용해서 해결하라고 안내주고 있습니다. 따라서, 입력값이 단순 숫자 혹은 영어의 형태가 아닐 것으로 예상되는 경우에 v-model 을 사용하는 것은 지양하는 것이 좋습니다. 참고로 여기에서의 IME 라 함은 "영어" 처럼 1byte 로 이루어진 언어가 아닌 "한글" 과 같은 언어를 컴퓨터가 입력받기 위해 필요한 "system software" 를 의미합니다. 

 

[ Example ]

1. 잘못된 사례

입력 값이 "영어"가 아닐 경우 사용자의 입력 값이 입력 값 그대로 value 에 할당되지 않을 수 있다. 

 

2. 올바른 사례 

input event 와 v-bind 를 사용해서 v-model 을 대체할 수 있다.

 

[ 참고 ]

- 예시에 사용 된 코드는 vue-cli (3.9.2 version) 로 생성한 프로젝트에 기반하고 있습니다.

 

https://github.com/GwangGeun/vueJs-blog-content/blob/master/src/views/Input.vue

 

- 공식 홈페이지 참고 내용  

 

https://kr.vuejs.org/v2/guide/forms.html

'Front-End > Vue.js & Vuex' 카테고리의 다른 글

mixin 사용시 주의점  (0) 2020.02.16
v-model 사용시 주의점 #2  (0) 2020.01.19

[ Content ]

computed 로 지정한 값을 v-model 에 사용하기 위해서는 computed 에 get 뿐만이 아닌 set 함수를 지정해줘야 합니다.
그렇지 않으면, 아래와 같은 에러를 볼 수 있습니다.

 

Computed property "model" was assigned to but it has no setter

 

[ Example ]

1. 잘못된 사례

  1-1) 예시 코드

 

위의 경우에는 computed 에 get 함수만 정의되어 있습니다.

 

  1-2) 실행 결과

 

error 발생과 함께 data binding 또한 제대로 이루어지고 있지 않은 상태임을 확인 할 수 있습니다.

 

 

2. 올바른 사례

  2-1) 예시 코드

 

이번에는 computed 에 get 뿐만이 아닌 set 함수도 정의되어 있습니다.

 

  2-2) 실행 결과 

 

위의 코드를 실행한 결과 위와 같이 에러 없이 잘 작동하는 것을 볼 수 있습니다.

 

[ 참고 ]

- 예시에 사용 된 코드는 vue-cli (3.9.2 version) 로 생성한 프로젝트에 기반하고 있습니다.

 

https://github.com/GwangGeun/vueJs-blog-content/blob/master/src/views/Vmodel.vue

 

- 공식 홈페이지 참고 내용  

 

https://vuejs.org/v2/guide/computed.html#Computed-Setter

 

Computed Properties and Watchers — Vue.js

Vue.js - The Progressive JavaScript Framework

vuejs.org

 

'Front-End > Vue.js & Vuex' 카테고리의 다른 글

mixin 사용시 주의점  (0) 2020.02.16
v-model 사용시 주의점 #1  (0) 2020.01.26

+ Recent posts