2021-03-25-TIL
2021-03-25-TIL
Transaction
트랜잭션은 여러 SQL 문을 하나의 작업 단위로 묶어, 모두 반영되거나 모두 취소되게 하는 것이다. 계좌 이체에서 출금만 되고 입금이 안 되는 상황을 막는 장치다. MySQL 문서에 따르면 START TRANSACTION(또는 BEGIN)으로 트랜잭션을 시작하고, COMMIT으로 변경을 확정하며, ROLLBACK으로 변경을 취소한다.
1
2
3
4
START TRANSACTION;
UPDATE account SET balance = balance - 1000 WHERE id = 1;
UPDATE account SET balance = balance + 1000 WHERE id = 2;
COMMIT;
MySQL은 기본적으로 autocommit 모드로 동작한다. 트랜잭션을 따로 시작하지 않으면 SQL 문 하나하나가 START TRANSACTION과 COMMIT으로 감싼 것처럼 실행되므로, 이미 실행한 문장을 ROLLBACK으로 되돌릴 수 없다.
@JsonProperty, @JsonIgnore
Jackson이 객체를 JSON으로 바꾸거나(직렬화) JSON을 객체로 바꿀 때(역직렬화) 필드를 어떻게 다룰지 정하는 어노테이션이다.
@JsonProperty: 필드나 getter/setter를 JSON 속성으로 쓰겠다고 표시한다. 값을 주지 않으면 필드 이름이 그대로 속성 이름이 되고,@JsonProperty("user_name")처럼 값을 주면 JSON에서는 그 이름을 쓴다.@JsonIgnore: 해당 속성을 직렬화와 역직렬화에서 모두 무시한다. 비밀번호처럼 응답에 내보내면 안 되는 필드에 붙인다.
1
2
3
4
5
6
7
public class User {
@JsonProperty("user_name")
private String name;
@JsonIgnore
private String password;
}
@JsonBackReference
양방향 연관 관계를 JSON으로 바꿀 때 쓰는 어노테이션이다. 예를 들어 질문(Question)이 답변 목록을 갖고 각 답변(Answer)도 자기 질문을 가리키면, 직렬화가 질문 → 답변 → 질문 → … 으로 끝없이 이어진다.
Jackson은 이 관계를 부모 쪽 @JsonManagedReference와 자식 쪽 @JsonBackReference로 나눠 표시하게 한다. Javadoc에 따르면 @JsonManagedReference가 붙은 속성은 평소처럼 직렬화되고, @JsonBackReference가 붙은 속성은 직렬화하지 않는다. 역직렬화할 때는 back 쪽 속성에 managed 쪽 객체를 다시 채워 넣어 양방향 연결을 복원한다.
1
2
3
4
5
6
7
8
9
public class Question {
@JsonManagedReference
private List<Answer> answers;
}
public class Answer {
@JsonBackReference
private Question question; // JSON에는 나가지 않는다
}
자바 리플렉션
리플렉션은 실행 중에 클래스의 필드, 메서드, 생성자 정보를 조회하고 사용하는 기능이다. java.lang.reflect 패키지 문서는 리플렉션이 로드된 클래스의 필드, 메서드, 생성자에 대한 정보에 프로그램이 접근하고, 이를 이용해 실제 대상을 다룰 수 있게 한다고 설명한다. Jackson이 처음 보는 클래스의 필드를 읽어 JSON을 만들 수 있는 것도, 스프링이 어노테이션을 보고 객체를 만들고 주입할 수 있는 것도 이 기능 덕분이다.
JavaScript event.preventDefault()
preventDefault()는 이벤트의 기본 동작을 막는다. MDN에 따르면 이 메서드는 이벤트를 명시적으로 처리하고 있으니 링크 이동이나 스크롤 같은 기본 동작을 하지 말라고 브라우저에 알린다. 이벤트 전파 자체는 멈추지 않는다.
폼의 제출 버튼을 누르면 브라우저는 기본으로 페이지를 이동하며 폼을 전송한다. AJAX로 직접 요청을 보내려면 submit 이벤트 핸들러에서 preventDefault()로 이 기본 제출을 막아야 한다.
1
2
3
4
form.addEventListener("submit", (event) => {
event.preventDefault(); // 페이지 이동을 막는다
fetch(form.action, { method: "POST", body: new FormData(form) });
});
Transient, 직렬화
Transient는 두 가지 맥락에서 나온다.
- Java의
transient키워드: JLS 8.3.1.3에 따르면 객체의 영속 상태에 속하지 않는 필드를 표시한다. Java 직렬화(Serializable)를 할 때 이 필드는 저장되지 않는다. - JPA의
@Transient: 엔티티의 필드나 속성이 영속 대상이 아니라고 표시한다. 즉 데이터베이스 컬럼에 매핑하지 않는다.
둘 다 “저장하지 않는다”는 뜻이지만 대상이 다르다. 앞의 것은 Java 직렬화 스트림, 뒤의 것은 데이터베이스다.
@Transactional flush
플러시는 JPA의 영속성 컨텍스트에 쌓인 변경을 데이터베이스에 반영(SQL 실행)하는 것이다. Hibernate 문서는 플러시를 영속성 컨텍스트의 상태를 데이터베이스와 동기화하는 과정이라고 설명한다. 엔티티를 저장하거나 수정해도 SQL이 바로 나가지 않고 영속성 컨텍스트에 모아 두었다가, 플러시 시점에 한꺼번에 실행된다.
Hibernate의 기본 플러시 모드(AUTO)는 트랜잭션을 커밋하기 직전, 쌓인 변경과 겹치는 JPQL/HQL 쿼리를 실행하기 직전, 그리고 네이티브 SQL 쿼리를 실행하기 전에 플러시한다. 그래서 @Transactional 메서드가 정상적으로 끝나 트랜잭션이 커밋될 때 변경이 데이터베이스에 반영된다. 플러시는 SQL을 보내는 것일 뿐 커밋이 아니므로, 플러시한 뒤라도 트랜잭션이 롤백되면 변경은 취소된다.
댓글
아직 댓글이 없습니다