package student;
import java.time.LocalDateTime;
//spring 패키지에서 WrongIdPasswordException 클래스를 import
import spring.WrongIdPasswordException;
public class Student {
private long sid; // 학생 ID를 저장하는 변수
private String phone; // 학생 전화번호를 저장하는 변수
private String passwd; // 학생 비밀번호를 저장하는 변수
private String name; // 학생 이름을 저장하는 변수
private LocalDateTime registerDateTime; // 학생 등록 일시를 저장하는 변수
public void setSid(long sid) { // sid 변수를 설정하는 메서드
this.sid = sid;
}
public long getSid() { // sid 변수를 반환하는 메서드
return sid;
}
public Student(String phone, String passwd, String name, LocalDateTime registerDateTime) { // 생성자 메서드
super();
this.phone = phone; // 전화번호를 인자로 받아 phone 변수에 저장
this.passwd = passwd; // 비밀번호를 인자로 받아 passwd 변수에 저장
this.name = name; // 이름을 인자로 받아 name 변수에 저장
this.registerDateTime = registerDateTime; // 등록 일시를 인자로 받아 registerDateTime 변수에 저장
}
public String getPhone() {
return phone;
}
public String getPasswd() {
return passwd;
}
public String getName() {
return name;
}
public LocalDateTime getRegisterDateTime() { // registerDateTime 변수를 반환하는 메서드
return registerDateTime;
}
// 비밀번호 변경 메서드
public void changePassword(String oldpasswd, String newpasswd) {
if (!passwd.equals(oldpasswd)) // 기존 비밀번호(oldpasswd)와 현재 비밀번호(passwd)가 다른 경우
throw new WrongIdPasswordException(); // WrongIdPasswordException 예외를 발생시킴
this.passwd = newpasswd; // 비밀번호를 새로운 비밀번호(newpasswd)로 변경
}
}
비밀번호 변경 시 기존 비밀번호와 현재 비밀번호가 다른 경우 예외 처리 상속
package student;
public class WrongIdPasswordException extends RuntimeException {
//비밀번호 변경 시 입력한 기존 비밀번호와 현재 비밀번호가 다른 경우 이 예외가 발생하도록 처리
}
DAO 정의
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class StudentDao {
private static long nextId = 0; // 다음 학생 ID를 생성하기 위한 정적 변수
private Map<String, Student> map = new HashMap<>();
// 학생 정보를 저장하기 위한 HashMap 컬렉션 생성 (키: 학생 전화번호, 값: 학생 객체)
public Student selectByPhone(String phone) {
// 전화번호(phone)를 기반으로 학생 정보를 조회하는 메서드
return map.get(phone); // HashMap에서 해당 전화번호를 키로 가지는 학생 객체를 반환
}
public void insert(Student student) {
// 학생 정보를 추가하는 메서드
student.setSid(++nextId); // 학생 객체에 다음 학생 ID를 설정
map.put(student.getPhone(), student); // HashMap에 학생 객체를 추가 (키: 전화번호, 값: 학생 객체)
}
public void update(Student student) {
// 학생 정보를 업데이트하는 메서드
map.put(student.getPhone(), student);
// HashMap에 새로운 학생 객체를 저장 (동일한 전화번호를 가진 학생 객체가 이미 존재하면 덮어씀)
}
public Collection<Student> selectAll() {
// 저장된 모든 학생 정보를 반환하는 메서드
return map.values(); // HashMap에 저장된 모든 학생 객체들의 컬렉션을 반환
}
}
학생가입 처리 관련 클래스
DTO, 학생 정보를 요청(request)하기 위한 클래스, 회원가입 할 때 비밀번호 같은지 확인
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class StudentRequest {
private String phone; // 학생 전화번호를 저장하는 변수
private String password; // 학생 비밀번호를 저장하는 변수
private String confirmPassword; // 비밀번호 확인을 위해 입력한 비밀번호를 저장하는 변수
private String name; // 학생 이름을 저장하는 변수
public boolean isPasswordEqualToConfirmPassword() {
// 비밀번호와 확인용 비밀번호가 일치하는지 확인하는 메서드
return password.equals(confirmPassword); // 비밀번호와 확인용 비밀번호를 비교하여 결과 반환
}
}
동일한 학생 정보가 존재하는 경우 사용자한태 알리는 예외처리
package student;
public class DuplicationStudentException extends RuntimeException {
// DuplicationStudentException 클래스를 정의하며 RuntimeException 클래스를 상속받음
public DuplicationStudentException(String message) {
// 생성자 메서드
super(message);
// 부모 클래스인 RuntimeException의 생성자를 호출하고, 인자로 전달된 메시지를 설정함
}
//동일한 전화번호를 가진 학생이 이미 등록되어 있으면 이 예외를 발생시키고
//해당 메시지를 사용자에게 알리는 용도로 사용
}
학생 정보 등록 서비스를 제공하는 클래스, StudentDao 객체를 의존성 주입
package student;
import java.time.LocalDateTime;
import spring.DuplicateMemberException;
public class StudentRegisterService {
private StudentDao studentDao;
// 생성자를 통해 StudentDao 객체를 주입받음
// 의존 객체를 생성자를 통해 주입한다.
public StudentRegisterService(StudentDao studentDao) {
this.studentDao = studentDao;
}
// 학생 등록을 수행하는 메서드
public Long regist(StudentRequest req) {
// 입력한 전화번호로 이미 등록된 학생이 있는지 조회
Student student = studentDao.selectByPhone(req.getPhone());
// 같은 전화번호를 가진 학생이 이미 존재하면 예외 발생
if (student != null) {
throw new DuplicateMemberException("dup phone " + req.getPhone());
// DuplicateMemberException 예외를 발생시키고 메시지를 설정하여 사용자에게 중복된 전화번호임을 알림
}
// 같은 전화번호를 가진 학생이 존재하지 않으면 DB에 삽입
Student newStudent = new Student(
req.getPhone(), req.getPassword(), req.getName(),
LocalDateTime.now());
studentDao.insert(newStudent); // 학생 정보를 DB에 삽입
// 새로 등록한 학생의 ID를 반환
return newStudent.getSid();
}
}
암호변경 관련 클래스
암호 변경 서비스 클래스
package student;
import spring.MemberNotFoundException;
public class StudentChangePasswordService {
private StudentDao studentDao; // StudentDao 객체를 참조하는 멤버 변수
public void changePassword(String phone, String oldPwd, String newPwd) {
// 학생의 비밀번호 변경 메서드
Student student = studentDao.selectByPhone(phone);
// 전화번호를 기반으로 학생 정보를 조회
if (student == null)
// 조회된 학생이 없으면 (해당 전화번호로 등록된 학생이 없으면)
throw new MemberNotFoundException();
// MemberNotFoundException 예외를 발생시킴
student.changePassword(oldPwd, newPwd);
// 학생 객체의 비밀번호 변경 메서드 호출 (기존 비밀번호를 새로운 비밀번호로 변경)
studentDao.update(student);
// 변경된 학생 정보를 업데이트 (DB에 반영)
}
public void setStudentDao(StudentDao studentDao) {
// StudentDao 객체를 주입하는 setter 메서드
this.studentDao = studentDao;
// 주입받은 StudentDao 객체를 멤버 변수에 설정
}
}
특정 학생 정보를 조회할 때, 해당 학생이 존재하지 않는 경우에 발생하는 예외처리
package student;
public class StudentNotFoundException extends RuntimeException {
// StudentNotFoundException은 RuntimeException의 하위 클래스이므로,
// 이 클래스는 Unchecked Exception으로 분류됨.
// Unchecked Exception은 명시적으로 예외를 처리하지 않아도 컴파일 시점에서 체크되지 않으며,
// 예외가 발생하면 런타임에 예외가 전파되어 프로그램 실행이 중단됨.
// 특정 학생 정보를 조회할 때, 해당 학생이 존재하지 않는 경우에 발생하는 예외로 사용될 수 있음.
// 예를 들어, 특정 학생의 ID를 기반으로 정보를 조회하는 메서드에서 해당 학생이 존재하지 않는 경우에
// 이 예외를 발생시키고 메시지를 설정하여 사용자에게 해당 학생을 찾을 수 없음을 알릴 수 있음.
}
객체 조립기
객체를 생성하고 의존 객체를 주입하는 기능을 제공한다. 또 한 특정 객체가 필요한 곳에 객체를 제공한다.
학생 정보와 관련된 객체들을 조립(Assemble)하는 클래스
package student;
public class AssemStudent {
// AssemStudent 클래스 정의
private StudentDao studentDao; // StudentDao 객체를 가리키는 멤버 변수
private StudentRegisterService SregSvc; // StudentRegisterService 객체를 가리키는 멤버 변수
private StudentChangePasswordService pwdSvc; // StudentChangePasswordService 객체를 가리키는 멤버 변수
public AssemStudent() {
// 생성자 메서드
studentDao = new StudentDao();
// 새로운 StudentDao 객체를 생성하여 studentDao 멤버 변수에 설정
SregSvc = new StudentRegisterService(studentDao);
// StudentRegisterService 객체를 생성하고 studentDao를 인자로 넘겨서 SregSvc 멤버 변수에 설정
pwdSvc = new StudentChangePasswordService();
// StudentChangePasswordService 객체를 생성하여 pwdSvc 멤버 변수에 설정
pwdSvc.setStudentDao(studentDao);
// pwdSvc의 setStudentDao 메서드를 사용하여 studentDao를 설정 (의존 객체 주입)
}
public StudentDao getStudentDao() {
// studentDao 멤버 변수를 반환하는 메서드
return studentDao;
}
public StudentRegisterService getStudentRegisterService() {
// SregSvc 멤버 변수를 반환하는 메서드
return SregSvc;
}
public StudentChangePasswordService getStudentChangePasswordService() {
// pwdSvc 멤버 변수를 반환하는 메서드
return pwdSvc;
}
}
실행
package student;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import spring.DuplicateMemberException;
import spring.MemberNotFoundException;
import spring.WrongIdPasswordException;
public class MainForAssemStudent {
public static void main(String[] args) throws IOException {
// 메인 메서드
BufferedReader reader =
new BufferedReader(new InputStreamReader(System.in));
// 사용자 입력을 받는 반복문
while (true) {
System.out.println("명령어를 입력하세요:");
String command = reader.readLine(); // 사용자 입력 받기
if (command.equalsIgnoreCase("exit")) {
System.out.println("종료합니다.");
break;
}
if (command.startsWith("new ")) {
// "new"로 시작하는 명령어 처리
processNewCommand(command.split(" "));
continue;
} else if (command.startsWith("change ")) {
// "change"로 시작하는 명령어 처리
processChangeCommand(command.split(" "));
continue;
}
printHelp(); // 잘못된 명령어일 경우 도움말 출력
}
}
private static AssemStudent assemStudent = new AssemStudent();
private static void processNewCommand(String[] arg) {
// "new" 명령어 처리
if (arg.length != 5) {
printHelp();
return;
}
StudentRegisterService SregSvc = assemStudent.getStudentRegisterService();
// AssemStudent에서 StudentRegisterService 객체를 가져옴
StudentRequest Sreq = new StudentRequest();
Sreq.setPhone(arg[1]);
Sreq.setName(arg[2]);
Sreq.setPassword(arg[3]);
Sreq.setConfirmPassword(arg[4]);
if (!Sreq.isPasswordEqualToConfirmPassword()) {
System.out.println("암호와 확인이 일치하지 않습니다.\n");
return;
}
try {
SregSvc.regist(Sreq);
// 학생 정보 등록을 수행
System.out.println("등록했습니다.\n");
} catch (DuplicateMemberException e) {
System.out.println("이미 존재하는 폰번호입니다.\n");
}
}
private static void processChangeCommand(String[] arg) {
// "change" 명령어 처리
if (arg.length != 4) {
printHelp();
return;
}
StudentChangePasswordService studentChangePasswordService =
assemStudent.getStudentChangePasswordService();
// AssemStudent에서 StudentChangePasswordService 객체를 가져옴
try {
studentChangePasswordService.changePassword(arg[1], arg[2], arg[3]);
// 학생 비밀번호 변경을 수행
System.out.println("암호를 변경했습니다.\n");
} catch (MemberNotFoundException e) {
System.out.println("존재하지 않는 폰번호입니다.\n");
} catch (WrongIdPasswordException e) {
System.out.println("폰번호와 암호가 일치하지 않습니다.\n");
}
}
private static void printHelp() {
// 도움말 출력
System.out.println();
System.out.println("잘못된 명령입니다. 아래 명령어 사용법을 확인하세요.");
System.out.println("명령어 사용법:");
System.out.println("new 폰번호 이름 암호 암호확인");
System.out.println("change 폰번호 현재비번 변경비번");
System.out.println();
}
}
예외 처리를 상속으로 처리하면 클래스파일이 추가로 생기지만 장점은 어디서 에러가 나는지 확인하기 쉽고
package chap02;
// 생성
public class Greeter {
// 멤버 변수 선언 - 문자열 형식을 저장하는 format 변수
// 문자열 형식이란, 예를 들어 "Hello, %s!"와 같이 %s 부분에 실제 이름이 들어가는 패턴을 말합니다.
private String format;
// 인자로 전달된 guest를 포맷에 맞추어 인사말을 생성하는 메서드
public String greet(String guest) {
// String.format 메서드를 사용하여 format 문자열에 guest를 삽입하여 최종 인사말 생성 후 반환
// guest는 파라미터(입력값)
return String.format(format, guest);
// String.format() 메서드를 사용하여 format 변수에 저장된 문자열 형식에 guest를 삽입하여 최종 인사말을 생성한 후 반환
}
// format 멤버 변수를 설정하는 메서드
// 외부에서 format 변수의 내용을 변경할 수 있음
public void setFormat(String format) {
this.format = format;
}
// 외부에서 해당 처럼 호출 가능
// // Greeter 객체 생성
// Greeter greeter = new Greeter();
//
// // 인사말 포맷 설정
// greeter.setFormat("Hello, %s!");
//
// // greet 메서드를 사용하여 인사말 생성
// String greetingMessage = greeter.greet("John");
// System.out.println(greetingMessage); // 출력 결과: "Hello, John!"
}
2. 스프링 설정 파일
package chap02;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// 등록
@Configuration
// Spring의 설정 클래스임을 나타내는 어노테이션
// Spring은 이 클래스를 참조하여 빈 등록과 의존성 주입을 처리
public class AppContext {
// 1. @Bean 어노테이션이 붙은 메서드는 Spring 컨텍스트에 빈으로 등록
@Bean
public Greeter greeter() {
// 2. Greeter 클래스의 인스턴스를 생성합니다.
Greeter g = new Greeter();
// 3. 인사 메시지의 형식을 설정합니다. "%s, 안녕하세요!"는 후에 사용자의 이름이 들어갈 위치를 나타낸다.
g.setFormat("%s, 안녕하세요!");
return g; // 설정이 완료된 Greeter 인스턴스를 반환
}
}
위의 코드를 사용하면 Spring 컨테이너가 Greeter 클래스의 인스턴스를 생성하고, 인사 메시지의 형식을 설정한 뒤,
해당 빈을 필요한 곳에서 주입하여 사용할 수 있게 된다.
3. 스프링이 제공하는 클래스를 이용해서 읽어와 사용하는 코드
package chap02;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main2 {
public static void main(String[] args) {
// 1. Spring 컨텍스트를 생성합니다. AppContext 클래스를 기반으로 새로운 컨텍스트를 만듭니다.
// // Spring 컨텍스트 초기화
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(AppContext.class);
// 2. 컨텍스트에서 "greeter" 빈을 가져옵니다. AppContext 클래스에서 빈으로 등록한 Greeter 클래스의 인스턴스를 반환
// String 컨테이너에서 Greeter 빈을 가져옴
Greeter g = ctx.getBean("greeter", Greeter.class);
// 3. Greeter 클래스의 greet 메서드를 호출하여 인사 메시지를 생성합니다. "스프링"을 인자로 주어서 "Greeter" 빈에 설정된 형식으로 인사 메시지를 생성
String msg = g.greet("스프링");
System.out.println(msg);
// 5. Spring 컨텍스트를 닫습니다.
ctx.close();
}
}
4. 결과
스프링은 객체 컨테이너
스프링의 핵심 기능은 객체를 생성하고 초기화 하는 것이다.
이와 관련된 기능은 ApplicationContext라는 인터페이스 정의 되어 있다. ( 위에 이미지 참조 )
위에 실행 코드에 AnnotationConfigApplicationContext 클래스는 이 인터페이스를 알맞게 구현한 클래스 중 하나
자바클래스에서 정보를 읽어와 객체 생성과 초기화를 수행 ( 개발자가 객체 생성과 초기화를 안해도 됨 )
BeanFactory 인터페이스는 객체 생성과 검색에 대한 기능을 정의 이외의 싱글톤, 프로토타입 빈인지 확인하는 기능도 제공
어떤 구현 클래스를 사용하든, 각 구현 클래스는 설정 정보로부터 빈(Bean)이라고 불리는 객체를 생성하고 그 객체를 내부에 보관한다. ( 객체를 서비스 )
싱글톤 객체
주소 값 같음 ( @Bean 1개 )
package chap02;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
// 싱글톤
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(AppContext.class);
// 주소 값 비교
// 주소 값은 같고 변수만 다름
Greeter g1 = ctx.getBean("greeter", Greeter.class);
Greeter g2 = ctx.getBean("greeter", Greeter.class);
System.out.println("(g1 == g2) = " + (g1 == g2));
ctx.close();
}
}
주소 값 다름 ( @Bean 2개 )
package chap02;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// 등록
@Configuration
public class AppContext {
// 1. @Bean 어노테이션이 붙은 메서드는 Spring 컨텍스트에 빈으로 등록
@Bean
public Greeter greeter() {
// 2. Greeter 클래스의 인스턴스를 생성합니다.
Greeter g = new Greeter();
// 3. 인사 메시지의 형식을 설정합니다. "%s, 안녕하세요!"는 후에 사용자의 이름이 들어갈 위치를 나타냅니다.
g.setFormat("%s, 안녕하세요!");
return g;
}
@Bean
public Greeter greeter2() {
// 2. Greeter 클래스의 인스턴스를 생성합니다.
Greeter g = new Greeter();
// 3. 인사 메시지의 형식을 설정합니다. "%s, 안녕하세요!"는 후에 사용자의 이름이 들어갈 위치를 나타냅니다.
g.setFormat("%s, 안녕하세요!");
return g;
}
}
package chap02;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
// 싱글톤
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(AppContext.class);
// 주소 값 비교
// 주소 값은 같고 변수만 다름
Greeter g1 = ctx.getBean("greeter", Greeter.class);
Greeter g2 = ctx.getBean("greeter2", Greeter.class);
System.out.println("(g1 == g2) = " + (g1 == g2));
ctx.close();
}
}
스프링 DI ( Dependency Injection )
DI는 우리말로는 '의존 주입'이라고 번역한다. 의존은 객체 간의 의존을 의미한다.
한 클래스가 다른 클래스의 메서드를 실행할 때 이를 '의존'한다고 표현
'의존'은 변경에 의해 영향을 받는 관계를 의미
의존 관계, 의존 처리 예제
Dao 클래스
package spring;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class MemberDao {
private static long nextId = 0;
private Map<String, Member> map = new HashMap<>();
public Member selectByEmail(String email) {
return map.get(email);
}
public void insert(Member member) {
member.setId(++nextId);
map.put(member.getEmail(), member);
}
public void update(Member member) {
map.put(member.getEmail(), member);
}
public Collection<Member> selectAll() {
return map.values();
}
}
의존 관계
package spring;
import java.time.LocalDateTime;
public class MemberRegisterService {
private MemberDao memberDao = new MemberDao();
// 회원 등록을 수행하는 메서드
public Long regist(RegisterRequest req) {
// 입력한 이메일로 이미 등록된 회원이 있는지 조회
Member member = memberDao.selectByEmail(req.getEmail());
// 같은 이메일을 가진 회원이 이미 존재하면 익셉션 발생
if (member != null) {
throw new DuplicateMemberException("dup email " + req.getEmail());
}
// 같은 이메일을 가진 회원이 존재하지 않으면 DB에 삽입
Member newMember = new Member(
req.getEmail(), req.getPassword(), req.getName(),
LocalDateTime.now());
memberDao.insert(newMember);
// 새로 등록한 회원의 ID를 반환
return newMember.getId();
}
}
MemberRegisterService 클래스가 MemberDao 클래스에 의존
의존하게 되면 MemberDao클래스의 insert() 메서드의 이름을 insertMember()로 변경하면 이 메서드를 사용하는 MemberRegisterService 클래스의 소스 코드도 함께 변경 된다. 이렇게 변경에 따른 영향이 전파되는 관계를 의존한다고 표현 한다. 클래스 내부에서 직접 의존 객체를 생성하는 것이 쉽긴 하나 유지보수 관점에서 문제점을 유발할 수 있다.
위에 코드 DI를 통한 의존 처리
직접 의존 객체를 생성했던 위에 코드와 달리 밑에 코드는 의존 객체를 직접 생성하지 않고 생성자를 통해서 의존객체를
전달 받는다. 즉 생성자를 통해 MemberRegisterService가 의존하고 있는 MemberDao 객체를 주입 받은 것이다.
DI를 하게 되면 코드가 더 길어지지만 사용하는 이유는 변경의 유연함이 있기 때문이다.
private MemberDao memberDao;
// 생성자를 통해 MemberDao 객체를 주입받음
// 의존 객체를 생성자를 통해 주입한다.
public MemberRegisterService(MemberDao memberDao) {
this.memberDao = memberDao;
}
package spring;
import java.time.LocalDateTime;
public class MemberRegisterService {
private MemberDao memberDao;
// 생성자를 통해 MemberDao 객체를 주입받음
// 의존 객체를 생성자를 통해 주입한다.
public MemberRegisterService(MemberDao memberDao) {
this.memberDao = memberDao;
}
// 회원 등록을 수행하는 메서드
public Long regist(RegisterRequest req) {
// 입력한 이메일로 이미 등록된 회원이 있는지 조회
Member member = memberDao.selectByEmail(req.getEmail());
// 같은 이메일을 가진 회원이 이미 존재하면 익셉션 발생
if (member != null) {
throw new DuplicateMemberException("dup email " + req.getEmail());
}
// 같은 이메일을 가진 회원이 존재하지 않으면 DB에 삽입
Member newMember = new Member(
req.getEmail(), req.getPassword(), req.getName(),
LocalDateTime.now());
memberDao.insert(newMember);
// 새로 등록한 회원의 ID를 반환
return newMember.getId();
}
}
DI와 의존 객체 변경의 유연함
예를 들어서 회원등록 기능이 가능한 클래스에 의존 객체를 생성하게 됫는데 암호변경 기능이 필요해서 암호 변경 클래스를 만들어서 똑같이 의존 객체를 생성하게 됫고 이상태에서 빠른 조회를 위해 캐시를 적용해야 하는 상황에서 의존 객체 클래스를 상속받은 캐시 클래스 생성하게 되면 회원등록 클래스랑 암호변경 클래스를 밑에 이미지 처럼 둘 다 변경해야 된다.
동일한 상황에서 DI를 사용해서 생성자를 통해서 의존 객체를 주입 받도록 구현하면 수정할 코드가 줄어든다.
이렇게 DI를 사용하면 MemberDao 객체를 사용하는 클래스가 세 개여도 변경할 곳은 의존 주입 대상이 되는 객체를
생성하는 코드 한 곳뿐이다. 의존객체를 직접 생성했던 방식에 비해 변경할 코드가 한 곳으로 집중되는 것을 알 수 있다.
오라클
트랜잭션 제어와 세션
하나의 단위로 데이터를 처리하는 트랜잭션
트랜잭션이란 더 이상 분할할 수 없는 최소 수행 단위를 뜻하며 계좌 이체와 같이 하나의 작업 또는 밀접하게 연관된 작업을 수행하기 위해 한 개 이상의 데이터 조작 명령어(DML)로 이루어진다. 즉 어떤 기능 한 가지를 수행하는 'SQL문 덩어리' 라고 볼 수 있다.
트랜잭션은 하나의 트랜잭션 내에 있는 여러 명령어를 한 번에 수행하여 작업을 완료하거나 아예 모두 수행하지 않는 상태, 즉 모든 작업을 취소한다. 이러한 특성으로 트랜잭션 의미를 'ALL OR NOTHING'문장으로 설명 하기도 한다. 그리고 트랜잭션을 제어하기 위해 사용하는 명령어를 TCL이라고 한다.
트랜잭션은 데이터베이스 계정을 통해 접속하는 동시에 시작 된다.
트랜잭션 예제
DEPT_TCL 테이블에 데이터를 입력 수정 삭제 하기
insert into dept_tcl values(50, 'DTABASE', 'SEOUL');
update dept_tcl set loc = 'BUSAN' where deptno = 40;
delete from dept_tcl where dname = 'RESEARCH';
select * from dept_tcl;
트랜잭션을 취소하고 싶을 때 ROLLBACK
ROLLBACK;
select * from dept_tcl;
트랜잭션을 영원히 반영하고 싶을 때 COMMIT
insert into dept_tcl values(50, 'DTABASE', 'SEOUL');
테스트를 위해 데이터 추가