- 트랜잭션이 데이터베이스에 모두 반영되던가, 아니면 전혀 반영되지 않아야 한다는 것
- 트랜잭션의 작업 처리 결과가 항상 일관성이 있어야 한다는 것
트랜잭션이 진행되는 동안에 데이터베이스가 변경되더라도 업데이트된 데이터베이스로 트랜잭션이 진행되는 것이 아니라, 처음에 트랜잭션을 진행하기 위해 참조한 데이터베이스로 진행된다.
- 둘 이상의 트랜잭션이 동시에 실행되고 있을 경우 어떤 하나의 트랜잭션이라도, 다른 트랜잭션의 연산에 끼어들 수 없다는 것
- 트랜잭션이 성공적으로 완료되었을 경우, 결과는 영구적으로 반영되어야 한다는 것

1. 활성(Active) : 트랜잭션이 정상적으로 진행중인 상태
트랜잭션이 시작되면, 해당 트랜잭션의 상태는 활동(Actice)상태가 된다.
해당 상태는 설계자가 설계한 대로 연산들이 정상적으로 실행중인 상태를 의미한다.
- 작업 성공시
2-1 부분완료(Partially Committed) : 트랜잭션의 마지막까지 실행되었지만, Commit 연산이 실행되기 직전의 상태
2-2 완료(Committed) : 트랜잭션이 성공이 종료되어 Commit 연산을 실행한 후의 상태
- 작업 실패시
2-1 실패(Failed) : 트랜잭션 실행에 오류가 발생하여 중단된 상태
2-2 철회(Aborted) : 트랜잭션이 비정상적으로 종료되어 Rollback 연산을 수행한 상태
commit
- 모든 작업들을 정상 처리하겠다고 확정하는 명령어
- 해당 처리 과정을 DB에 영구 저장하겠다는 의미
- Commit을 수행하면 하나의 트랜잭션 과정이 종료되는 것
- Commit을 수행하면 이전 데이터가 완전히 반영되어 UPDATE 된다.
rollback
- 작업 중 문제가 발생되어 트랜잭션의 처리 과정에서 발생한 변경사항을 취소하는 명령어
- 해당 명령을 트랜잭션에게 하달하면, 트랜잭션은 시작되기 이전의 상태로 되돌아간다.
- 마지막 Commit을 완료한 시점으로 돌아간다는 뜻
- 즉, Commit하여 저장한 예전 상태를 복구하는 것
savepoint
- 현재의 트랜잭션을 작게 분할하는 명령어
- 저장된 savepoint는 rollback to savepoint문을 사용하여 표시한 곳까지 rollback 할 수 있다.
- 원칙대로라면 원자성을 보장해야 하지만, 매우 긴 트랜잭션의 경우 대부분의 로직이 수행됐는데 마지막에만 문제가 생겨 Rollback이 되면 문제가 발생하지 않은 영역까지 반복해야 하는 난감한 상황이 발생한다.
- 때문에 개발자가 임의적으로 현재의 트랜잭션을 작게 분할하여 지정한 곳까지 rollback 할 수 있어 이러한 문제를 해결한다.
-- 테이블 생성
CREATE TABLE employees (
employee_id INT PRIMARY KEY,
name VARCHAR(100),
department VARCHAR(50),
salary DECIMAL(10, 2)
);
-- 데이터 삽입
INSERT INTO employees (employee_id, name, department, salary) VALUES (1, 'Alice', 'Sales', 50000);
INSERT INTO employees (employee_id, name, department, salary) VALUES (2, 'Bob', 'Engineering', 60000);
INSERT INTO employees (employee_id, name, department, salary) VALUES (3, 'Charlie', 'Sales', 55000);
INSERT INTO employees (employee_id, name, department, salary) VALUES (4, 'Diana', 'Engineering', 70000);
-- employees 테이블 확인
select * from employees;

-- commit 예시
BEGIN TRANSACTION;
-- Sales 부서 직원들의 급여를 10% 인상
UPDATE employees SET salary = salary * 1.1 WHERE department = 'Sales';
-- 변경 사항을 데이터베이스에 확정
COMMIT;
-- 결과 확인
SELECT * FROM employees;

-- rollback 예시
BEGIN TRANSACTION;
-- Sales 부서 직원들의 급여를 10% 인상
UPDATE employees SET salary = salary * 1.1 WHERE department = 'Sales';
-- 변경 사항을 취소
ROLLBACK;
-- 결과 확인
SELECT * FROM employees;

-- save transaction과 rollback transaction 예시
BEGIN TRANSACTION;
-- Sales 부서 직원들의 급여를 10% 인상
UPDATE employees SET salary = salary * 1.1 WHERE department = 'Sales';
-- SAVE TRANSACTION 설정
SAVE TRANSACTION my_savepoint;
-- Engineering 부서 직원들의 급여를 5% 인상
UPDATE employees SET salary = salary * 1.05 WHERE department = 'Engineering';
-- SAVE TRANSACTION으로 롤백
ROLLBACK TRANSACTION my_savepoint;
-- 나머지 변경 사항을 확정
COMMIT TRANSACTION;
-- 결과 확인
SELECT * FROM employees;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
@Transactional
public void registerUser(User user) {
// 사용자 등록 로직
userRepository.save(user);
// 추가적인 로직
}
}
isolation
- 트랜잭션에서 일관성 없는 데이터 허용 수준을 설정한다.
- 트랜잭션의 격리 수준을 설정한다.
- 데이터베이스의 동시성 제어 방법을 정의한다.
- 주요 격리 수준에는 READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE 등이 있다.
@Transactional(isolation = Isolation.SERIALIZABLE) public void someMethod() { // 높은 수준의 격리 }
- READ_UNCOMMITTED: 가장 낮은 격리 수준으로, 다른 트랜잭션의 커밋되지 않은 변경 사항을 읽을 수 있다.
- READ_COMMITTED: 커밋된 데이터만 읽을 수 있다. 기본 격리 수준이다.
- REPEATABLE_READ: 트랜잭션이 시작된 시점 이후 변경된 데이터는 읽을 수 없다.
- SERIALIZABLE: 가장 높은 격리 수준으로, 모든 트랜잭션이 순차적으로 실행된 것처럼 보인다.
propagation
- 트랜잭션 동작 도중 다른 트랜잭션을 호출할 때, 어떻게 할 것인지 지정하는 옵션이다.
- 트랜잭션의 전파 방식을 정의한다.
- 트랜잭션이 이미 존재하는지, 또는 새로운 트랜잭션을 시작해야 하는지 결정한다.
- 주요 전파 옵션에는 REQUIRED, REQUIRES_NEW, MANDATORY, SUPPORTS, NOT_SUPPORTED, NEVER, NESTED 등이 있다.
@Transactional(propagation = Propagation.REQUIRES_NEW) public void someMethod() { // 새로운 트랜잭션을 시작 }전파 옵션
REQUIRED: 기본값으로, 이미 존재하는 트랜잭션이 있으면 이를 사용하고, 없으면 새로운 트랜잭션을 시작한다.
REQUIRES_NEW: 항상 새로운 트랜잭션을 시작하며, 기존 트랜잭션이 있으면 이를 일시적으로 중단한다.
MANDATORY: 이미 존재하는 트랜잭션이 있어야 하며, 없으면 예외를 발생시킨다.
SUPPORTS: 기존 트랜잭션이 있으면 이를 사용하고, 없으면 트랜잭션 없이 실행한다.
NOT_SUPPORTED: 트랜잭션 없이 실행하며, 현재 트랜잭션이 있으면 이를 일시적으로 중단한다.
NEVER: 트랜잭션 없이 실행해야 하며, 현재 트랜잭션이 있으면 예외를 발생시킨다.
NESTED: 트랜잭션의 중첩을 허용합니다. 내부 트랜잭션이 실패하면 외부 트랜잭션은 영향을 받지 않는다.
noRollbackfor
- 특정 예외 발생 시 rollback하지 않는다.
@Transactional(noRollbackFor = AnotherException.class) public void someMethod() throws AnotherException { // AnotherException 발생 시 롤백하지 않음 }
rollbackFor
- 특정 예외 발생 시 rollback한다.
@Transactional(rollbackFor = CustomException.class) public void someMethod() throws CustomException { // CustomException 발생 시 롤백 }
timeout
- 지정한 시간 내에 메소드 수행이 완료되지 않으면 rollback한다(-1일 경우 timeout을 사용하지 않는다)
@Transactional(timeout = 30) public void someMethod() { // 30초 후 타임아웃 }
readOnly
- 트랜잭션을 읽기 전용으로 설정한다.
DEFAULT
- 기본 격리 수준
- DB의 isolation level을 따른다
READ_UNCOMMITED(level 0)
- 커밋되지 않는 데이터에 대한 읽기를 허용
READ_COMMITED(level 1)
- 커밋된 데이터에 대해 읽기 허용
REPEATABLE_READ(level 2)
- 동일 필드에 대해 다중 접근 시 모두 동일한 결과를 보장
SERIALIZABLE(level 3)
- 가장 높은 격리, 성능 저하의 우려가 있음
1. DAO(Data Access Object)
- 데이터베이스와 상호작용하는 객체
- 데이터베이스 작업을 캡슐화하고, 데이터베이스에 대한 CRUD(Create, Read, Update, Delete) 연산을 수행하는 메서드를 제공한다
특징
- 데이터 접근 캡슐화 : 데이터베이스에 대한 접근 로직을 한 곳에 모아 관리한다.
- 비즈니스 로직과 분리 : 데이터베이스 작업을 비즈니스 로직에서 분리하여, 코드의 유지보수성을 높인다
- 인터페이스 구현 : DAO 인터페이스를 정의하고, 이를 구현한 클래스가 데이터베이스 작업을 실제로 수행한다.
public interface UserDAO { void insertUser(User user); User getUserById(int id); void updateUser(User user); void deleteUser(int id); } public class UserDAOImpl implements UserDAO { // 데이터베이스 연결을 위한 코드 @Override public void insertUser(User user) { // SQL INSERT 작업 } @Override public User getUserById(int id) { // SQL SELECT 작업 return new User(); // 실제 데이터 반환 } @Override public void updateUser(User user) { // SQL UPDATE 작업 } @Override public void deleteUser(int id) { // SQL DELETE 작업 } }
2. VO(Value Object)
- 데이터 객체의 일종으로, 데이터를 담기 위한 객체
- 주로 데이터의 상태를 보존하고, 이 데이터가 변경되지 않도록 설계된다.
특징
- 불변성 : VO는 불변 객체(Immutable Object)로 설계되는 경우가 많다. 즉, 객체가 생성된 이후에는 데이터가 변경되지 않는다.
- 비즈니스 의미 : VO는 비즈니스 로직에서 의미 있는 데이터 집합을 표현한다.
public class AddressVO { private final String street; private final String city; private final String zipCode; public AddressVO(String street, String city, String zipCode) { this.street = street; this.city = city; this.zipCode = zipCode; } // getter 메서드 public String getStreet() { return street; } public String getCity() { return city; } public String getZipCode() { return zipCode; } }
3. DTO(Data Transfer Object)
- 데이터 전송 객체로, 계층 간 또는 시스템 간 데이터 전송을 위해 사용된다.
- 데이터의 구조를 정의하고, 데이터를 저장하는 역할을 한다.
- 주로 네트워크 통신이나 데이터베이스에서 결과를 반환할 때 사용된다.
특징
- 전송 목적 : 데이터 전송을 위해 필요한 필드만 포함된다.
- 빈 객체 : DTO는 데이터만 담고 있으며, 비즈니스 로직을 포함하지 않는다
- 일반적으로 직렬화 가능 : 네트워크 통신이나 파일 저장을 위해 직렬화(Serializable) 가능한 경우가 많다.
public class UserDTO { private int id; private String name; private String email; // 기본 생성자 public UserDTO() {} // 파라미터가 있는 생성자 public UserDTO(int id, String name, String email) { this.id = id; this.name = name; this.email = email; } // getter 및 setter 메서드 public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
4. DO(Domain Object)
- 도메인 객체로, 도메인 모델을 표현하는 객체이다.
- 비즈니스 로직과 규칙을 포함하며, 시스템의 도메인 모델을 구성하는 클래스이다.
- 일반적으로 도메인의 핵심 엔티티를 모델링한다.
특징
- 비즈니스 로직: 도메인 모델과 관련된 비즈니스 로직을 포함할 수 있다.
- 엔티티 : 데이터베이스의 엔티티와 매핑될 수 있으며, 비즈니스 규칙을 표현한다.
public class UserDO { private int id; private String name; private String email; public UserDO(int id, String name, String email) { this.id = id; this.name = name; this.email = email; } // 비즈니스 로직 public void updateEmail(String newEmail) { // 이메일 업데이트 로직 this.email = newEmail; } // getter 및 setter 메서드 public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
- DAO(Data Access Object) : 데이터베이스와 상호작용을 하는 객체로, 데이터 접근 로직을 캡슐화한다.
- VO(Value Object) : 데이터의 불변성을 유지하며, 비즈니스 의미를 가지는 객체이다.
- DTO(Data Transfer Object) : 데이터 전송을 위해 사용되는 객체로, 데이터의 구조를 정의한다
- DO(Domain Object) : 도메인 모델을 표현하며, 비즈니스 로직과 규칙을 포함한다.