아무런 생각 없이 JpaResitory의 save()
만 사용하다가,
saveAndFlush()
라는 메소드도 있다는 것을 알게 되었다.
둘 다 엔티티를 저장하는 것으로 보이는데, 차이가 뭐가 있을까 ..?
@Transactional
@Override
public <S extends T> S save(S entity) {
Assert.notNull(entity, "Entity must not be null");
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
@Transactional
@Override
public <S extends T> S saveAndFlush(S entity) {
S result = save(entity);
flush();
return result;
}
두 메소드의 차이는 flush()
여부였다.
flush()
를 날리면 영속성 컨텍스트에서 DB 트랜잭션 쪽으로 쿼리문이 날라가게 된다.
그러니까, 메소드 실행 시, flush()
를 바로 날려서 DB 트랜잭션으로 쿼리문이 날라가도록 하냐, 하지 않냐의 차이!
commit은 .. JPA에서 알아서 해주는 건가보다 ..
오류는 에러(Error) 와 예외(Exception)으로 나눌 수 있다.
에러(Error)
: 시스템 레벨에서 발생하는 심각한 수준의 오류. 개발자가 미리 예측할 수 없으므로 개발 시 신경쓰지 않아도 되는 점.
예외(Exception)
: 로직에서 발생하는 오류. 개발자가 구현한 코드에서 발생하므로 개발자가 미리 예측할 수 있고, 상황에 맞게 처리할 수 있음.
Exception은 크게 두 가지로 나눈다. Checked와 Uncheked로 나눈다.
Checked Exception | Unchecked Exception | |
---|---|---|
애플리케이션 예외 처리 | 반드시 예외 처리 코드가 있어야 함 | 강제는 아님 |
예외 발견 시점 | 컴파일 시점 | 런타임 시점 |
Rollback 여부 | Rollback X | Rollback O |
대표 클래스 | Exception을 상속받는 클래스 중, RuntimeException을 제외한 예외클래스 (ex. IOException, SQLException) | RuntimeException을 상속받는 모든 클래스 (ex. NullPointerException, IllegalArgumentException) |
Checked Exception과 Unchecked Exception의 차이점 중 하나인 Rollback 여부이다.
Checked Exception은 Rollback이 되지 않는다.
이는 Spring이 EJB 관습을 따르기 때문이라고 한다.
EJB (Enterprise Java Bean) 란 ?
- 기업 환경의 시스템을 구현하기 위한 서버 측의 컴포넌트 모델
- 일반적으로 업무 로직을 갖고 있는 서버 어플리케이션을 부르는 말
Enterprise Bean
: 비지니스 로직을 탑제한 부품컨테이너
: Database 처리, Transaction 처리 등 시스템 서비스를 이용한 로직을 감추고 있는 부품
반면, 에너테이션을 사용하든 AOP 설정을 하든 Spring은 Uncheked Exception과 Error 발생 시 Rollback하는 것을 기본 원칙으로 따른다.
(Checked Exception은 컴파일 시 확인 가능하므로 이 예외에서는 Rollback을 해주지 않는 듯 하다..!)
하지만 Checked Exception에서 항상 Rollback이 안되는 것은 아니고, 가능하게 설정할 수 도 있다.
@Transactional(rollbackFor = Exception.class)
Spring에 존재하는 RollbackRuleAttribute 클래스가 있는데,
이 타입의 리스트에 Exception을 추가해주면 된다 !
<참고>
먼저, AWS에 S3 Bucket을 생성한다.
버킷 이름에는 언더바(_)
나 대문자(A-Z)
를 사용할 수 없다!
(나는 객체 소유권은 권장으로 설정했다.)
방법을 많이 찾아보았는데, 나는 S3 Bucket을 만들기 전에 IAM을 먼저 만들어두었기 때문에 권한 설정을 따로 해주지는 않았다.
즉 처음에 IAM 사용자를 만들 때, 권한을 이미 부여했기 때문에 따로 권한을 줄 필요가 없었다.
다만, 엑세스 키
는 생성해주어야 한다 !
그래야 접근할 수 있기 때문이다.
생성된 엑세스 키에 대한 내용은 꼭 !!! 꼭 !! csv 파일로 저장해두어야 한다.
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
aws를 사용하기 위한 의존성을 추가해준다. (gradle 기반)
application.properties에 위에서 만든 Bucket
와 엑세스 키
에 대한 정보를 입력한다.
조심해야 할 것은, gitHub에 절대절대절대 올리면 안된다는 것이다.
공개적으로 올려버리면, 해킹당할 위험이 있기 때문이다.
나는 .gitignore
에 미리 application.properties
파일을 올려두었다.
// 경로가 기억이 안난다 ..
..경로/..경로/application.properties
해당 파일의 경로에 맞춰서 넣어주기만 하면 된다 !
이미 gitHub에 올라간 상태라면 파일 내용을 미리 복사해두고, gitHub에서 삭제했다가 pull 해와서 ignore에 코드를 추가하고, 다시 application.properties 파일을 만들어주면 된다!
(다른 내용들은 미리 commit 꼭 해둬야 날라가지 않는다)
# S3
cloud.aws.credentials.accessKey={자신의 accessKey}
cloud.aws.credentials.secretKey={자신의 secretKey}
cloud.aws.s3.bucket={만들어진 Bucket의 이름}
cloud.aws.region.static=ap-northeast-2 // 지역을 넣으면 된다
cloud.aws.stack.auto-=false
@Configuration
public class S3Config {
@Value("${cloud.aws.credentials.accessKey}")
private String accessKey;
@Value("${cloud.aws.credentials.secretKey}")
private String secretKey;
@Value("${cloud.aws.region.static}")
private String region;
@Bean
public AmazonS3 amazonS3Client() {
AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
return AmazonS3ClientBuilder
.standard()
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.withRegion(region)
.build();
}
}
AmazonS3를 사용하기 위해서 S3Config 파일을 작성해준다.
application.properties에 미리 작성해두었던 값들을 가져와 AmazonS3Client 객체를 만들고,
Bean으로 주입하여 사용할 수 있게 만들어준다!