트랜잭션이 필요한 이유

매우 자주 데이터베이스로 작업할 때 다양한 작업을 수행해야 하는 상황이 발생하지만 함께 사용해야 의미가 있습니다.

예를 들어, 우리는 다음 세 가지를 수행하는 뱅킹 소프트웨어를 작성하고 있습니다.

  • 고객의 계좌에서 돈을 인출
  • 수취인 계좌에 금액 추가
  • 게시 데이터를 "게시 로그"에 기록

이러한 작업을 실행하는 동안 오류가 발생하면 다른 두 작업도 취소해야 합니다. 클라이언트에서 돈을 쓰고 수취인에게 추가하지 않는 것은 불가능합니까? 글쎄, 아니면 수신자에게 추가하지만 클라이언트에서 쓰지 않습니까?

따라서 서로 다른 작업을 하나로 논리적으로 그룹화한 것을 트랜잭션 이라고 합니다 . 즉, 트랜잭션은 모두 함께 수행되어야 하는 작업 그룹 입니다 . 작업이 실패했거나 오류와 함께 실행된 경우 다른 모든 작업을 취소해야 합니다.

트랜잭션에는 일반적으로 세 가지 상태가 있습니다.

  • 초기 상태 - 작업 그룹을 실행하기 전의 시스템 상태
  • 성공 상태 - 작업 그룹이 완료된 후의 상태
  • 실패한 상태 - 문제가 발생했습니다.

이 경우 일반적으로 세 가지 명령이 있습니다.

  • 시작/시작 - 논리적 작업 그룹이 시작되기 전에 실행됩니다.
  • 커밋 - 트랜잭션 작업 그룹 이후에 실행
  • 롤백 - 시스템을 실패 상태에서 초기 상태로 되돌리는 프로세스를 시작합니다.

이렇게 작동합니다.

먼저 트랜잭션을 열어야 합니다. begin() 또는 start() 메서드를 호출합니다 . 이 메서드를 호출하면 문제가 발생할 경우 반환을 시도할 시스템 상태를 나타냅니다.

그런 다음 논리적 그룹인 트랜잭션으로 결합되는 모든 작업이 수행됩니다.

그런 다음 commit() 메서드가 호출됩니다 . 호출은 논리적인 작업 그룹의 끝을 표시하고 일반적으로 이러한 작업을 실행하는 프로세스를 시작합니다.

FileWriter에서 어떻게 작성했는지 기억해 보십시오. 먼저 작성한 모든 내용은 메모리에 저장되고 flush() 메서드가 호출되면 메모리의 버퍼에 있는 모든 데이터가 디스크에 기록됩니다. 이 flush() 는 트랜잭션 커밋입니다.

음, 트랜잭션 작업 중에 오류가 발생하면 시작 상태로 돌아가는 프로세스를 시작해야 합니다. 이 프로세스를 rollback() 이라고 하며 일반적으로 동일한 이름의 메서드가 이를 담당합니다.

대략적으로 말하자면 거래를 완료하는 방법에는 두 가지가 있습니다.

  • COMMIT - 모든 변경 사항을 확인합니다.
  • ROLLBACK - 모든 변경 사항을 롤백합니다.

JDBC의 트랜잭션

거의 모든 DBMS는 트랜잭션과 함께 작동할 수 있습니다. 따라서 JDBC도 이 경우를 지원합니다. 모든 것이 매우 간단하게 구현됩니다.

첫째, Statement 객체의 execute() 메서드에 대한 각 호출은 별도의 트랜잭션에서 실행됩니다. 이를 위해 Connection에는 AutoCommit 매개변수가 있습니다 . true 로 설정되면 execute () 메서드를 호출할 때마다 commit() 이 호출됩니다 .

둘째, 하나의 트랜잭션에서 여러 명령을 실행하려는 경우 다음과 같이 할 수 있습니다.

  • 자동 커밋 비활성화
  • 우리의 명령을 호출
  • commit() 메서드를 명시적으로 호출

매우 간단해 보입니다.

connection.setAutoCommit(false);

Statement statement = connection.createStatement();
int rowsCount1 = statement.executeUpdate("UPDATE  employee SET salary = salary+1000");
int rowsCount2 = statement.executeUpdate("UPDATE  employee SET salary = salary+1000");
int rowsCount3 = statement.executeUpdate("UPDATE  employee SET salary = salary+1000");

connection.commit();

commit() 메서드가 실행되는 동안 서버에서 오류가 발생하면 SQL 서버는 세 가지 작업을 모두 취소합니다.

그러나 클라이언트 측에서 여전히 오류가 발생하고 commit() 메서드 호출에 도달하지 못하는 상황이 있습니다 .

connection.setAutoCommit(false);

Statement statement = connection.createStatement();
int rowsCount1 = statement.executeUpdate("UPDATE  employee SET salary = salary+1000");
int rowsCount2 = statement.executeUpdate("UPDATE  employee SET salary = salary+1000");
int rowsCount3 = statement.executeUpdate("UPDATE multiple typos will result in an exception");

connection.commit();

하나의 executeUpdate() 실행 중에 오류가 발생하면 commit () 메서드가 호출되지 않습니다. 수행된 모든 작업을 롤백하려면 rollback() 메서드를 호출해야 합니다 . 일반적으로 다음과 같습니다.

try{
  	connection.setAutoCommit(false);

  	Statement statement = connection.createStatement();
  	int rowsCount1 = statement.executeUpdate("UPDATE  employee SET salary = salary+1000");
  	int rowsCount2 = statement.executeUpdate("UPDATE  employee SET salary = salary+1000");
  	int rowsCount3 = statement.executeUpdate("UPDATE multiple typos will result in an exception");

	  connection.commit();
 }
 catch (Exception e) {
   connection.rollback();
}

세이브포인트

JDBC 3.0의 등장으로 트랜잭션 롤백으로 보다 효율적인 작업이 가능해졌습니다. 이제 세이브 포인트 - 세이브 포인트를 설정할 수 있으며 롤백() 오퍼레이션을 호출하면 특정 세이브 포인트로 롤백됩니다.

저장하려면 다음 명령을 사용하여 저장점을 생성해야 합니다.

Savepoint save = connection.setSavepoint();

다음 명령을 사용하여 저장점으로 되돌립니다.

connection.rollback(save);

문제가 있는 명령 앞에 저장점을 추가해 보겠습니다.

try{
  	connection.setAutoCommit(false);

  	Statement statement = connection.createStatement();
  	int rowsCount1 = statement.executeUpdate("UPDATE  employee SET salary = salary+1000");
  	int rowsCount2 = statement.executeUpdate("UPDATE  employee SET salary = salary+1000");

  	Savepoint save = connection.setSavepoint();
 	 try{
      	int rowsCount3 = statement.executeUpdate("UPDATE multiple typos will result in an exception");
 	 }
 	 catch (Exception e) {
    	   connection.rollback(save);
 	 }

	  connection.commit();
 }
 catch (Exception e) {
   connection.rollback();
}

문제가 있는 메서드를 호출하기 전에 저장 지점을 추가하고 rollback(save) 메서드를 호출하여 저장된 상태로 돌아가는 방식으로 중첩된 트랜잭션을 구성했습니다 .

예, 게임의 저장/불러오기와 매우 유사합니다.