서비스 계층의 역할
비즈니스 로직을 갖는다
여러 SQL에 접속하는 경우 트랜잭션 관리
트랜잭션이란?
쪼갤 수 없는 업무의 최소 단위
"모든 작업이 성공해야 최종적으로 적용됨"을 보장
모든 SQL을 성공시키거나, 하나라도 실패하면 모두 실패시킴
MySQL 트랜잭션 명령어(SQL)
start transaction;
트랜잭션 시작하기
commit;
트랜잭션 정상 종료 (트랜잭션 시작 후 실행된 모든 SQL 한번에 반영)
rollback;
트랜잭션 실패 처리 (트랜잭션 시작 후 실행된 모든 SQL 미반영)
실습
트랜잭션 실행 후, 테이블에 값 저장. 이 상태에서 다른 MySQL 창에서 해당 테이블의 정보를 검색하면


트랜잭션이 시작된 후 아직 commit이나 rollback으로 이 트랜잭션의 반영 여부를 알려주지 않았기 때문에, 다른 단말에서는 트랜잭션 시작 후의 SQL의 결과물을 아직 확인할 수 없음


데이터 하나 더 추가해주고 commit;으로 모든 SQL을 반영한 후 결과를 확인해보면

여기서 commit;이 아닌 rollback; 처리하면 아무런 정보도 user table에 저장되지 않는다.
SringBoot에서 트랜잭션 사용하기
@Transactional
이 어노테이션을 함수에 붙이면, 그 함수가 시작될 때 transaction이 시작되고, 종료될 때 commit이나 롤백을 해주도록 적용할 수 있다.
해당 함수가 시작될 때 start transaction; (트랜잭션 시작)
함수가 예외(에러) 없이 잘 끝났다면 commit;
문제가 있다면 rollback;
(기준은 @Transactional 메서드의 정상 종료 여부)

함수에 이 어노테이션을 붙여주기만 하면 트랜잭션 적용 끝.. ^^
@Transactional(readOnly = true)
이 옵션을 주면, 트랜잭션을 썼을 때 저장, 업데이트, 삭제 등 데이터 변경을 위한 불필요한 기능이 빠지기 때문에 약간의 성능적 이점이 있다.
만약 트랜잭션을 걸어주지 않으면, 어떤 함수의 동작이 일어난 후 다른 코드에서 문제가 발생해도, 예외 발생 알림은 떠도 정상 종료된 함수는 웹에 반영되는 일이 발생할 수 있음. 온라인 주문을 했는데 돈은 빠져나갔는데 주문내역은 없다거나!
함수가 한 몸이 아니라, 음 저장했네 저장. 오 에러낫네 에러. 이런식으로 한 줄씩 처리
주의
Checked Exception은 트랜잭션 내에서 발생하더라도 롤백이 일어나지 않는다. (IOException 등)
영속성 컨텍스트?
테이블과 매핑된 Entity 객체를 관리/보관하는 역할
스프링에서는 트랜잭션을 사용하면 영속성 컨텍스트가 생겨나고, 트랜잭션이 종료되면 영속성 컨텍스트가 종료된다
특징
1. 변경 감지 (Dirty Check)
영속성 컨텍스트 안에서 불러와진 Entity는 명시적으로 save하지 않더라도 변경을 감지해 자동으로 저장된다.
public void deleteUser(String name) {
// select * from user where name = ?;
User user = userRepository.findByName(name).orElseThrow(IllegalArgumentException::new);
if (user == null) {
throw new IllegalArgumentException();
}
userRepository.delete(user);
//userRepository.save(user);
}
여기서 save함수가 없어도 db에 자동 업데이트 된다는 뜻
변경 작업이 영속성 컨텍스트 범위 안에서 이루어져서 발생할 수 있는 일
2. 쓰기 지연
DB에 INSERT / UPDATE / DELETE SQL을 바로 날리는 것이 아니라, 트랜잭션이 commit될 때 모아서 한 번만 날린다.
그때그때 날릴 것을 한번에 모아서 날리는 것이므로 효율적
3. 1차 캐싱
ID를 기준으로 Entity를 기억한다.
만약 같은 id로 유저를 세번 조회한다고 했을 때, 첫 번째 해당 id로 유저를 조회했을 때 그걸 영속성 컨텍스트가 기억하고 있따가, 두 번째 동일한 코드가 실행됐을 때 또다시 데이터베이스와 통신하는 것이 아니라 영속성 컨텍스트가 갖고 있는 유저 정보를 넘겨줌. 세번째도 마찬가지
최초 한 번만 데이터를 조회하고, 그 후에는 한 번 조회한 데이터는 계속 사용할 수 있다는 장점
이렇게 캐싱된 객체는 완전히 동일하다. (주소값까지 동일하다는 말)
4. 지연 로딩
연결되어 있는 객체를 꼭 필요한 순간에 가져온다.
'스프링부트' 카테고리의 다른 글
| [SpringBoot] 연관관계 (0) | 2025.03.15 |
|---|---|
| [SpringBoot] Spring Data JPA를 사용한 CRUD (0) | 2025.03.10 |
| [SpringBoot][DB] JPA (이용 배경, 개념, table과 객체 맵핑 실습) (0) | 2025.03.09 |
| [SpringBoot] Spring Container (0) | 2025.03.09 |
| [SpringBoot] Layered Architecture: Controller, Service, Repository (0) | 2025.03.08 |