트랜잭션 Transaction?
: 트랜잭션이란 데이터베이스의 상태를 변화시키기 위해 수행하는 작업의 단위, 또는 한꺼번에 모두 수행되어야할 일련의 연산을 뜻함
원자성...일관성...독립성...영속성....(ACID)
Spring과 Java에서의 트랜잭션
Spring의 @Transactional
: Transactional의 경우 class위와 method위에 어노테이션을 붙여줄 수 있다. class의 경우 내부에 있는 각각의 method를 트랜잭션화 한다는 것으로 method에 추가로 붙이면 method에 붙은 걸 우선 적용후 class 트랜잭션이 적용된다.
예제 1. @Transactional(rollbackFor = Exception.class) 사용
@Transactional(rollbackFor = Exception.class)
public void putBookAndAuthor() throws Exception{
Book book = new Book();
book.setName("Java Start");
bookRepository.save(book);
Author author = new Author();
author.setName("martin");
authorRepository.save(author);
// Exception 발생하여 @Transactional 어노테이션 사용시 Transaction에 있는 쿼리들이 롤백
throw new Exception("Error : not db commit");
}
결과 : rollback 시키도록 동작
....(중략)
Books : []
....(중략)
Authors : []
설명 : Transactional 내에서 개발자가 강제로 Exception을 실행시키는 코드를 넣을 때는 Checked Exception인지 UnChecked Exception인지 확인을 해야한다.
Unchecked Exception이 발생하면 트랜잭션 내용이 rollback 되고,
Checked Exception은 트랜잭션 내에서 발생하여도 rollback되지 않고 반영된다.
@Transactional의 옵션
※ @Trnasactional은 Proxy 기반이며 AOP로 구성되어 있음. 즉 Method가 실행되기전에 트랜잭션을 묶는다. 메소드 A가 메소드 B의 상위 메소드이더라도 A에 @Trnasactional이 없다면 B에 선언도있더라도 전이되지 않음
다수의 트랜잭션이 동시에 실행되면 여러 문제가 발생하게 된다.
* Dirty Read : 트랜잭션 a가 수정 중인 (not commit) 데이터를 트랜잭션 b가 Read 할 경우, 트랜잭션 a 가 롤백되면 트랜잭션 b의 데이터는 잘못된 데이터를 Read하게 된다.
* Non-repeatable Read : 트랜잭션 a가 어떤 데이터 A를 2번 조회하는 연산으로 이루어 졌다고 하면 트랜잭션 a는 A를 한 번 읽은 후, 트랜잭션 b가 A를 수정하고 commit한다면, 트랜잭션 a는 다시 A를 읽을 때 수정된 데이터가 조회된다.
* phantom read : 트랜잭션 a가 데이터A 를 2번 조회하는 연산으로 이루어졌다고 가정할 때, 트랜잭션 a가 A를 조회해서 데이터 1,2,3,4,5의 데이터를 얻은 후, 트랜잭션 b가 A에 6,7을 추가할 경우, 트랜잭션 a가 다시 A를 조회하면 결과 집합이 달라진다.
1. isolation
: 트랜잭션의 격리 수준이란
* DEFAULT : 기본 격리 수준(DB의 격리 수준)
* READ_UNCOMMITTED : 다른 트랜잭션에서 commit 되지 않은 내용도 참조
* READ_COMMITTED : 다른 트랜잭션에서 commite되 내용만 참조
* REPEATABLE_READ : 트랜잭션에 진입하기 이전에 커밋된 내용만 참조
* SERIALIZABLE :트랜잭션에 진입하면 Lock을 걸어 다른 트랜잭션이 접근하지 못하게 함
동시에 여러 트랜잭션이 처리될 때 !
1.1 특정 트랜잭션이 다른 트랜잭션에서 변경하거나,
1.2 조회하는 데이터들을 볼 수 있도록 허용할지 말지를 결정.
/*
* @Transactional default option
*/
@Transactional
public void getDefault(Long id){
System.out.println("getbook1 : "+bookRepository.findById(id));
System.out.println("getbook1 : "+bookRepository.findAll());
System.out.println("getbook2 : "+bookRepository.findById(id));
System.out.println("getbook2 : "+bookRepository.findAll());
}
/*
* @Transactional isolation.READ_UNCOMMITTED
*/
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void getReadUnCommit(Long id){
System.out.println("getbook1 : "+bookRepository.findById(id));
System.out.println("getbook1 : "+bookRepository.findAll());
System.out.println("getbook2 : "+bookRepository.findById(id));
System.out.println("getbook2 : "+bookRepository.findAll());
Book book = bookRepository.findById(id).get();
book.setName("jpa master");
bookRepository.save(book);
}
/*
* @Transactional isolation.READ_COMMITTED
*/
@Transactional(isolation = Isolation.READ_COMMITTED)
public void getReadCommit(Long id){
System.out.println("getbook1 : "+bookRepository.findById(id));
System.out.println("getbook1 : "+bookRepository.findAll());
//entityManager.clear();
System.out.println("getbook2 : "+bookRepository.findById(id));
System.out.println("getbook2 : "+bookRepository.findAll());
//entityManager.clear();
/* Book book = bookRepository.findById(id).get();
book.setName("jpa master");
bookRepository.save(book);*/
}
/*
* @Transactional isolation.REPEATABLE_READ
*/
@Transactional(isolation = Isolation.REPEATABLE_READ)
public void getRepetableCommit(Long id){
System.out.println("getbook1 : "+bookRepository.findById(id));
System.out.println("getbook1 : "+bookRepository.findAll());
entityManager.clear();
System.out.println("getbook2 : "+bookRepository.findById(id));
System.out.println("getbook2 : "+bookRepository.findAll());
bookRepository.update();
entityManager.clear();
}
/*
* @Transactional isolation.SERIALIZABLE
*/
@Transactional(isolation = Isolation.SERIALIZABLE)
public void getSerializableCommit(Long id){
System.out.println("getbook1 : "+bookRepository.findById(id));
System.out.println("getbook1 : "+bookRepository.findAll());
entityManager.clear();
System.out.println("getbook2 : "+bookRepository.findById(id));
System.out.println("getbook2 : "+bookRepository.findAll());
bookRepository.update();
entityManager.clear();
}
2. propagation
: 트랜잭션을 어떻게 전파시킬 것인지에 대한 옵션, 첫번째 상위 메소드가 가지고 있던 트랜잭션을 하위 메소드 자체에서 트랜잭션을 만들어서 따로 사용할 것이냐를 설정하는 것.
* REQUIRED : 필요시 새로 생성(Ex. JPA의 save() 메소드)
* REQUIRES_NEW : 트랜잭션이 필요하면 기존에 존재하여도 새로 만들어 따로 관리.
* Propagation.SUPPORTS : 타 메소드에서 호출할 때 트랜잭션이 있으면 해당 트랜잭션을 호출해서 사용.없다면 굳이 생성하지 않고 처리.
* NOT_SUPPORTED : 상위 트랜잭션이 있으면 중지시키고 없이 실행
* MANDATORY : 상위 트랜잭션이 있어야하면 사용하며, 없을 경우 예외 발생
* NEVER : MANDATORY의 반대
* NESTED : 별개의 트랜잭션을 사용하여 별개로 commit되거나 rollback 처리되나, 호출하는 메소드에서 롤백이 일어나면, 호출하는 메소드, 호출 메소드 모두 롤백 처리
@Transactional(propagation = Propagation.REQUIRED)
public void putPropagation(){
Author author = new Author();
author.setName("martins");
authorRepository.save(author);
throw new RuntimeException("Error : 트랜잭션 오류발생");
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void putPropagationNew(){
Author author = new Author();
author.setName("martins");
authorRepository.save(author);
throw new RuntimeException("Error : 트랜잭션 오류발생");
}
@Transactional(propagation = Propagation.NESTED)
public void putPropagationNested(){
Author author = new Author();
author.setName("martins");
authorRepository.save(author);
throw new RuntimeException("Error : 트랜잭션 오류발생");
}
Reference
FastCampus - 한번에 끝내는 Java/Spring 웹 개발 마스터 초격차 패키지 Online
https://fastcampus.co.kr/dev_online_javaend
한 번에 끝내는 Java/Spring 웹 개발 마스터 초격차 패키지 Online. | 패스트캠퍼스
Java/Spring 웹 개발, 핵심 25가지 스킬부터 공부하세요. 대기업 출신 7인의 강사진이 모여 만든 Java/Spring 웹 개발 완전체 커리큘럼! 핵심 스킬 25가지 강의부터 250개의 예제, 7개의 프로젝트까지! 비
fastcampus.co.kr
[데이터베이스] 트랜잭션 격리수준
https://joont92.github.io/db/%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98-%EA%B2%A9%EB%A6%AC-%EC%88%98%EC%A4%80-isolation-level/https://mozi.tistory
velog.io
https://velog.io/@seongwon97/Spring-Boot-Transaction-Manager
[Spring JPA] Transaction Manager
Spring Boot에서 트랜젝션 적용 - Spring Boot에서 하나의 method를 트렌젝션으로 적용하는 방법은 method위에 @Transactional어노테이션을 붙여주면 된다.
velog.io
https://velog.io/@max9106/Transaction
[정리] Transaction(트랜잭션)
@Transactional 애노테이션을 클래스나, 메서드에 붙여주면 트랜잭션 기능이 적용된 프록시 객체가 생성된다.이 프록시 객체는 @Transactional이 포함된 메소드가 호출 될 경우, PlatformTransactionManager를
velog.io
'Spring > 1-3. JPA' 카테고리의 다른 글
(9. Spring Data JPA) @Query 와 Native Query (0) | 2023.05.23 |
---|---|
(8. Spring Data JPA) 영속성 전이 Cascade (0) | 2023.05.11 |
(6. Spring Data JPA) 영속성 컨텍스트 Persistence Context (0) | 2023.05.06 |
(5. Spring Data JPA) Entity Listener 활용 (1) | 2022.10.18 |
(4. Spring Data JPA) Entity의 기본속성(@Entity) (0) | 2022.10.17 |