본문 바로가기
PHP

[PHP] 데이터베이스 트랜잭션 처리하는 방법

by teamnova 2024. 1. 5.

안녕하세요 오늘은 PHP에서 데이터베이스 트랜잭션을 처리하는 방법을 알아보겠습니다.

 

저희가 코딩을 하며 프로그램을 짜다보면 다양한 예외상황을 맞이하게 되는 데 그럴 때마다 저희는 예외처리를 통해 데이터들을 롤백해주거나 재시도 하는 작업을 하죠? 그런 게 데이터베이스 트랜잭션을 처리하는 과정입니다.

 

하지만 그 과정을 좀 더 쉽게 만들어주는 메소드가 있습니다!

그것은 바로 mysqli_rollback() 메소드로 해당 스크립트에서 이전에 했던 작업들을 전부 롤백시키는 기능을 합니다.

 

예를 들어 돈을 송금하는 스크립트인데 데이터베이스에서는 돈을 출금했다고 잔액을 깎는 쿼리가 실행되었는데 그 후 전산상에 문제가 생겨 실제 송금에는 실패했을 경우 잔액이 사라지는 문제가 생깁니다.

이 때 당연히 저희는 그 쿼리를 되돌려줘야 하는 데 되돌려야 하는 작업이 여러개라면 번거로워지죠?

이런 경우에 방금 말한 mysqli_rollback()메소드를 사용하면 됩니다!

 

먼저 PHP에서는 기본적은로 AUTO_COMMIT이 활성화 되어있어 실행되는 쿼리가 바로 데이터베이스에 반영됩니다.

하지만 데이터베이스 트랜잭션 처리를 하기 위해선 AUTO_COMMIT을 비활성화 시켜야 합니다.

그래야 쿼리를 실행시켜도 즉각적으로 데이터베이스에 반영되지 않습니다.

 

처리 순서는 다음과 같습니다.

1. mysqli_autocommit 함수를 통해 autocommit 비활성화(false)

2. insert, delete 작업 등

3. 만약 실패시 mysqli_rollback 함수를 통해 데이터 롤백

4. 최종 성공시 mysqli_commit (수동 커밋)

5. mysqli_autocommit 함수를 통해 autocommit 활성화(true)

 

다음은 예제 코드입니다.

사용자 테이블에 사용자 정보를 입력함과 동시에 반드시 카테고리, 사용자의 이미지 패스를 저장해야 합니다.

이 때 카테고리 및 사용자 이미지패스를 저장할 때 한번이라도 실패하는 경우 데이터를 롤백해주겠습니다.

class Database { // 데이터베이스 관련 클래스
	
	private $host_name = "localhost";
	private $host_id = "root";
	private $host_password = "root";
	private $db_name = "test";
	private $conn;

	private function __construct() { // db 객체 초기화
		$this->conn = mysqli_connect($this->host_name, $this->user_name, $this->user_password);
		mysqli_select_db($this->conn, $this->db_name);
		mysqli_set_charset($this->conn, "utf8");		
    	}

	public function get_insert_id() { // 저장된 마지막 PK 값 가져오는 메소드
		$id = mysqli_insert_id($this->conn);
		return $id;
	}

	// 사용자 정보 저장 및 카테고리, 이미지 패스 저장 메소
	public function addMember($user_id, $title, $context, $thumbnail_path, $image_path, $category) {
		// mysqli_begin_transaction($this->conn); 해당 코드를 오토커밋 방식 대신 사용할 수도 있다.
		mysqli_autocommit($this->conn, FALSE);
		$query = "INSERT INTO `member` VALUES (NULL , '{$user_id}', '{$title}', '{$context}', NOW(), '{$thumbnail_path}')";
		
		$result = @mysqli_query($this->conn, $query);
		$id = get_insert_id();
		
		if ($result) {
			
			foreach($category as $value) { // 카테고리 저장 및 실패 시 롤백				
				$result = $this->addCategory($id, $value);
				if (!$result) {
					mysqli_rollback($this->conn);	
					return FALSE;
				}			
			}
			
			foreach($image_path as $path) { // 이미지 패스 저장 및 실패 시 롤백
				$result = $this->addImage($id, $path);
				if (!$result) {
					mysqli_rollback($this->conn);	
					return FALSE;
				}
			}			
			
			mysqli_commit($this->conn);	
			mysqli_autocommit($this->conn, TRUE);
			return TRUE;		
		}
		return FALSE;
	}	

	//카테고리 추가
	public function addCategory($user_id, $category_id) {
		$query = "INSERT INTO `member_categorys` VALUES (NULL, '{$user_id}', '{$category_id}')";
		$result = @mysqli_query($this->conn, $query);
		return $result;
	}	

	//이미지 추가
	public function addImage($user_id, $image_path) {
		$query = "INSERT INTO `member_images` VALUES (NULL, '{$user_id}', '{$image_path}')";
		$result = @mysqli_query($this->conn, $query);
		return $result;
	}
	
}

 

이렇게 롤백 메소드를 사용하면 편리하게 데이터베이스 트랜잭션을 처리할 수 있습니다~
감사합니다.