1. 지속적인 배포를 해보자
어제 하지 못하고 넘겼던, CD를 직접해보았다. CD는 다음과 같이 진행했다.
-
S3 생성
- 코드를 저장 할 저장소를 생성해줘야한다.
-
EC2 에서 S3 FullAccess 허용 및 EC2 태그 설정
- CodeDeploy 시 S3에서 코드를 가져오기 때문에 허용해줘야함.
- CodeDeploy 시 대상 EC2를 태그를 이용해 찾아오기 때문에 태그를 설정해줘야함.
-
CodeDeploy 권한 생성 및 Codedeploy 어플리케이션 추가
- CodeDeploy 전용 권한을 생성 한 뒤, Codydeploy어플리케이션을 추가하여 역할을 부여함.
- EC2에 CodeDeploy Agent install 및 2번에서 설정한 태그를 이용해 Codydeploy 어플리케이션 측에서 EC2 - CodeDeploy 연결
-
github actions 에서 사용할 사용자를 생성하고 IAM을 할당
- S3에 파일을 업로드하고, Codedeploy를 실행시켜 파일배포작업을 수행하도록 큐를 줘야하기 때문에, S3 FullAccess와 Codedeploy FullAccess IAM 을 생성한다.
- github actions 에 셋팅할 사용자를 만들고, 위에서 만든 IAM을 할당한다. 또한 github actions에 등록할 수 있도록 ACCESSKEY, SECRETKEY를 발급받는다.
-
Codedeploy 시 사용할 appspec.yml 작성
- Codedeploy는 파일의 appspec.yml 을 읽고 그에 따라 코드를 배포를 해준다. 따라서, 이곳에는 파일을 배포할 위치나 권한등의 정보를 넣어 작성해준다.
-
EC2에서 실행시킬 start.sh와 stop.sh를 작성한다.
- appspec.yml 에 해당 스크립트의 위치와 경로가 적혀있으며, 기존에 사용하던 서버를 끄고 -> 다시 빌드하여 시작할 수 있도록 셋팅한다.
-
.github/workflow 재작성
- 이전과 모든 과정을 거치고,
aws deploy
를 run 하여, s3에 코드를 업로드하고, codedeploy를 실핼 할 수 있도록 스크립트를 재작성한다.
- 이전과 모든 과정을 거치고,
중간에 github actions가 동작하지 않는 이슈가 있었다. 해당 이슈는 스크립트를 아예 덮어쓰면서 발생했는데, 기존 스크립트에 한줄한줄 추가하면서 해결했다. 하지만, 아직 정확한 원인을 밝혀내지 못해서 github actions 메커니즘 공부할 겸 원인을 알아보려고 한다.
2. 심화 JPA
JPA 는 영속성이라는 기능을 통해RDB를 객체지향적으로 사용할 수 있게 만들어준 라이브러리이다. JPA 이전에는 DB를 어떻게 다뤘을까?
JDBC
의 등장- JAVA와 DB간의 연결을 관리하기 위해서 나온 기능이다.
JDBC Driver Manager
는Connect
->Statement
->ResultSet
이라는 것을 순차적으로 호출하여 쿼리를 수행하고 그 결과를 반환하도록 설계했다.- 일일히 모든 단계를 열고 닫아줘야하기 때문에, 번거로움이 발생했다.
QueryMapper
의 등장- JDBC를 사용하면 중복로직을 계속적으로 작성해야한다거나, open과 close 등의 트랜젝션 라이프사이클을 일일히 관리해줘야하기 때문에 번거로운 상황들이 많이 발생했다. 따라서, 영속성이라는 상태를 부여하여, 위의 번거로운 과정을 대신해줄수 있는
QueryMappe
r가 등장하였다. JDBC Template
는 Connection, Statement, ResultSet 반복적 처리 대신 해주고,RowMapper
를 이용하여, ResultSet을 VO에 손쉽게 맵핑해서 사용가능 하도록 만들어주었다.Mybatis
는 SQL과 Mapper을 따로 작성하여 관리할 수 있도록 해주고, 미리 작성한 sql문을 mapper에 설정된 interface와 연결함으로서, 쿼리의 결과를 손쉽게 받아올 수 있도록하였다. 하지만, sql를 직접작성하는 것은 번거로운 일이기 때문에, 대처방안이 필요했다.- ORM의 등장
- ORM은 객체를 하나의 테이블과 연관지음으로서, 어플리케이션에서 DB를 신경쓰지 않고 객체지향적으로 사용할 수 있도록 도와주었다. 이는 객체지향이 갖고있는 디자인패턴등을 활용하여, DB를 사용할 수 있게됨을 의미한다.
- 하지만, DB와 객체의 관계는 동일한 모양이 아니기 때문에, 상속문제, 관계문제, 밀도문제, 식별성문제등 해결할 문제들이 있었고, 이를 잘 해결해 나감으로서 ORM은 DB을 하나의 객체와 연결짓는 것이 가능해졌다.
- 이것이 가능해짐으로서, 1차캐시와 2차캐시와 같이 객체지향의 캐싱기능을 이용하여, 쿼리를 최적화 시킬 수 있었다.
- flush는 DB에 쿼리문을 날리는 것을 의미하며, 이 전까지는 1차캐시에서 쓰기 지연을 통해 쿼리를 최적화시킨다. 즉, 같은 테이블에 비슷한 요청이 들어오거나 합칠 수 있는 로직들은 flush이전에 영속성컨택스트에서 최적화하여 DB 발송한다는 것이다. 즉, 여러번 날릴 쿼리를 하나로 합쳐서 보낸다는것이다. (PK생성전략이 IDENTITY인 경우 제외)
- flush이전도 데이터 조회가 가능한데, 그이유는 1차캐시에서 가져오기 때문이다. 하지만, 이것은 실제로 DB 반영된 데이터가 아니기에 적절한 사용이 필요하다.
- 기타 알게된 정보들
@Enumerated
는 String으로 사용한다. 이유는ORDINARY
로 사용하게 되면 나중에 ID값이 바뀔경우 사이드이펙트가 커진다.Cascade
,orphanRemoval
는 영속성을 전파하기위한 용도로 쓰이며, 부모엔티티에 쓰인다. (DB는 자식에 쓴다.)Cascade.REMOVE
은 부모에서 자식을 삭제할 경우 자식엔티티를 제거하지않는다. 이유는, 관계의 삭제가 엔티티의 제거와 동일한 개념이 아니기 때문이다.orphanRemoval
은 위에서 발생한 고아 엔티티를 삭제할 수 있도록 설정해주기 위한 셋팅이다.Cascade.ALL + orphanRemoval=ture
의 조합은 자식과 부모의 라이프사이클을 동일하게 만들어주는 조합이다.EAGER
은 부모엔티티가 조회되면 자식엔티티의 실제객체도 받아오는 설정이다.-
LAZY
는 부모엔티티가 조회되면 자신엔티티를 받아오지 않고, 나중에 필요한 시점에 조회하는 설정이다.- 기본타입은 LAZY로 두되, 필요한 곳에 fetch join을 이용하여, 실제객체를 가져올 수 있도록 셋팅해준다.