Entity - #3. JPA 트랜잭션 (데이터 변경 SQL을 DB에 요청 및 반영하기 위해서는 트랜잭션 필요)
트랜잭션이란?
트랜잭션
: DB 데이터들의 무결성과 정합성을 유지하기 위한 하나의 논리적 개념
: 데이터베이스의 데이터들을 안전하게 관리하기 위해서 생겨난 개념
가장 큰 특징)
여러 개의 SQL이 하나의 트랜잭션에 포함될 수 있음
→ 모든 SQL이 성공적으로 수행되면 DB에 영구적으로 변경 반영 / 단 하나라도 실패하면 모든 변경 되돌림
MySQL에서 직접 트랜잭션 사용해보기
mySQL 콘솔에 붙여넣기
START TRANSACTION; # 트랜잭션을 시작합니다.
INSERT INTO memo (id, username, contents) VALUES (1, 'Robbie', 'Robbie Memo');
INSERT INTO memo (id, username, contents) VALUES (2, 'Robbert', 'Robbert Memo');
SELECT * FROM memo;
COMMIT; # 트랜잭션을 커밋합니다.
SELECT * FROM memo;
하나씩 ctrl + enter해서 실행
Insert까지 하면 실제 데이터베이스가 생성되진 않으나 조회는 됨
Commit하면 트랜잭션이 커밋되고 종료
영속성 컨텍스트에다 Entity 객체를 저장했다고 해서 데이터 베이스에 바로 반영되는 것 x
JPA에서도 영속성 컨텍스트로 관리하고 있던 Entity 객체들의 정보를
쓰기 지연 저장소에 전부 가지고 있다가 커밋이 되면 변경할 요청을 반영함
데이터베이스에 트랜잭션을 적용하면 효율적임
실수 등 만약의 상황을 대비, 마지막으로 진짜 문제가 없을 때 한 번에 반영하는게 훨씬 더 효율적
영속성 컨텍스트 확인하는 테스트 코드
1. Entity Transaction 성공 테스트
1) EntityTest.java에 붙여넣기
@Test
@DisplayName("EntityTransaction 성공 테스트")
void test1() {
EntityTransaction et = em.getTransaction(); // EntityManager 에서 EntityTransaction 을 가져옵니다.
et.begin(); // 트랜잭션을 시작합니다.
try { // DB 작업을 수행합니다.
Memo memo = new Memo(); // 저장할 Entity 객체를 생성합니다.
memo.setId(1L); // 식별자 값을 넣어줍니다.
memo.setUsername("Robbie");
memo.setContents("영속성 컨텍스트와 트랜잭션 이해하기");
em.persist(memo); // EntityManager 사용하여 memo 객체를 영속성 컨텍스트에 저장합니다.
et.commit(); // 오류가 발생하지 않고 정상적으로 수행되었다면 commit 을 호출합니다.
// commit 이 호출되면서 DB 에 수행한 DB 작업들이 반영됩니다.
} catch (Exception ex) {
ex.printStackTrace();
et.rollback(); // DB 작업 중 오류 발생 시 rollback 을 호출합니다.
} finally {
em.close(); // 사용한 EntityManager 를 종료합니다.
}
emf.close(); // 사용한 EntityManagerFactory 를 종료합니다.
}
처음에 오류가 뜨면 Setter이 없어서 그럼
2) Memo.java 클래스에 @Getter 추가 (alt + insert > getter 및 setter)
주의사항) EntityClass에서 Setter을 이용할 때는 데이터베이스와 맵핑되니까 조심해야 함
package com.sparta.entity;
import jakarta.persistence.*;
@Entity // JPA가 관리할 수 있는 Entity 클래스 지정
@Table(name = "memo") // 매핑할 테이블의 이름을 지정
public class Memo {
@Id
// 테스트 때는 빼주기
// @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// nullable: null 허용 여부
// unique: 중복 허용 여부 (false 일때 중복 허용)
@Column(name = "username", nullable = false, unique = true)
private String username;
// length: 컬럼 길이 지정
@Column(name = "contents", nullable = false, length = 500)
private String contents;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getContents() {
return contents;
}
public void setContents(String contents) {
this.contents = contents;
}
}
3) debug 시작 > 아래 페이지 참고
인텔리제이 - Debugging하는 법
1. 빨간색 누르기 2. 우측 버튼 누르기 > All로 된거 Thread로 바꾸고 Make Default 눌러주기 3. 이제 저 play버튼 누르면 디버그 가능 주의사항) 테스트할 때는 직접 id값을 넣어줄 거라서 @GeneratedValue
luminous0115.tistory.com
EntityTest.java 상세 설명
@Test
@DisplayName("EntityTransaction 성공 테스트")
void test1() {
EntityTransaction et = em.getTransaction(); // EntityManager 에서 EntityTransaction 을 가져옵니다.
et.begin(); // 트랜잭션을 시작합니다.아래 설정해둔 내용들이 실행됨
try { // DB 작업을 수행할 때 발생하는 오류 잡기 위함
Memo memo = new Memo(); // 저장할 Entity 객체를 생성합니다.
memo.setId(1L); // 식별자 값을 넣어줍니다.
memo.setUsername("Robbie");
memo.setContents("영속성 컨텍스트와 트랜잭션 이해하기");
em.persist(memo); // EntityManager 사용하여 memo 객체를 영속성 컨텍스트에 저장합니다.
et.commit(); // 오류가 발생하지 않고 정상적으로 수행되었다면 commit 을 호출합니다.
// commit 이 호출되면서 DB 에 수행한 DB 작업들이 반영됩니다.
} catch (Exception ex) {
ex.printStackTrace();
et.rollback(); // DB 작업 중 오류 발생 시 rollback 호출
} finally {
em.close(); // 사용한 EntityManager 를 종료
}
emf.close(); // 사용한 EntityManagerFactory 를 종료
}
- em.persist(memo);
- 영속성 컨텍스트에 저장하고 싶은 Entity Class 객체를 ()안에 넣어주면 영속성 컨텍스트에 담기게 됨
- debug 콘솔 > em > persistenceContext > Memo#1의 #1 중요함
- debug 콘솔 > em > persistenceContext > entitiesByKey보면 Memo#1이 저장되어 있음
identifier = PK
value = Memo Entity가 저장됨
- 실제로 JPA에서 트랜잭션 사용하기
- EntityTransaction et = em.getTransaction(); : EntityManager에서 EntityTransaction 가지고 올 수 있음
- et.begin(); // 트랜잭션 시작 - 아래 설정해둔 환경이 실행됨
2. Entity Transaction 실패 테스트
@Test
@DisplayName("EntityTransaction 실패 테스트")
void test2() {
EntityTransaction et = em.getTransaction(); // EntityManager 에서 EntityTransaction 을 가져옵니다.
et.begin(); // 트랜잭션을 시작합니다.
try { // DB 작업을 수행합니다.
Memo memo = new Memo(); // 저장할 Entity 객체를 생성합니다.
memo.setUsername("Robbert");
memo.setContents("실패 케이스");
em.persist(memo); // EntityManager 사용하여 memo 객체를 영속성 컨텍스트에 저장합니다.
et.commit(); // 오류가 발생하지 않고 정상적으로 수행되었다면 commit 을 호출합니다.
// commit 이 호출되면서 DB 에 수행한 DB 작업들이 반영됩니다.
} catch (Exception ex) {
System.out.println("식별자 값을 넣어주지 않아 오류가 발생했습니다.");
ex.printStackTrace();
et.rollback(); // DB 작업 중 오류 발생 시 rollback 을 호출합니다.
} finally {
em.close(); // 사용한 EntityManager 를 종료합니다.
}
emf.close(); // 사용한 EntityManagerFactory 를 종료합니다.
}
ㄴ Auto Increment를 빼놓았기 때문에 식별자 값을 필수로 지정해야 한다는 오류가 발생