====== 트랜잭션 가이드 ====== ===== 개요 ===== 트랜잭션이란 * 간단히 말해 여러 query의 수행결과(주로 insert, update, delete)를 하나의 그룹으로 묶어 동시에 반영(commit) 혹은 반영 취소(rollback)를 진행하기 위해 DB platform에서 제공하는 기술이다. * 사전적인 정의는 [[https://ko.wikipedia.org/wiki/%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98|위키 참조]] Kantukan ERP 에서의 트랜잭션 * 칸투칸 ERP에서는 기본적으로 codeIgniter에서 제공하는 트랜잭션을 활용함 * 그러나 보다 쉬운 활용 및 향후 공통 업데이트를 위해 KTK_model에 관련 트랜잭션 지원기능을 추가하여 해당 라이브러리 활용할 것을 권장 ===== 사용법 ===== ==== 사용 범위 ==== 트랜잭션은 특성 상 Business layer (Model)에서만 활용 가능 (기술적으로는 다른 layer에서도 활용 가능하나 해당 프로젝트를 포함한 일반적인 프로젝트에서는 보통 금지합니다.) ==== 자동 트랜잭션 ==== 자동 트랜잭션이란 commit, rollback 을 프레임웍에서 자동으로 결정하여 진행하는 트랜잭션 방식이다. === 트랜잭션 시작 === 트랜잭션 시작 시 관련 datasource 이름을 지정할 수 있다 (미 지정시, default 활용) === 트랜잭션 종료 === 트랜잭션 종료도 시작과 마찬가지로 datasource 이름 지정이 가능하며 미 지정시 역시 default 를 사용한다. === 트랜잭션 결과 자동 판별 규칙 === 트랜잭션 시작과 종료 중의 쿼리 - 동일 datasource 를 활용하는 - 중에 오류가 없을 시 자동으로 commit이 진행된다. 예) * not null field에 null 값을 insert 혹은 update 시 * 관련 쿼리 실패 및 같은 트랜잭션 구간 내의 모든 쿼리 롤백 진행 * update 시 where 조건에 의해 업데이트 되는 row가 하나도 없을 시 * 쿼리 자체는 성공하였기 때문에 트랜잭션 성공으로 간주 구간 내의 모든 쿼리가 commit 됨 === 소스 상에서의 트랜잭션 결과 확인 방법 === 트랜잭션 종료 시 return 값(true, false)을 통해 트랜잭션의 결과를 확인 할 수 있다. === 사용 예제 === /** * KTK_Model 을 extends한 model에서만 공용 트랜잭션 활용 가능 * controller 등에서 트랜잭션 사용 금지 */ class Prototype_model extends KTK_Model { /** * 트랜잭션 테스트 method */ function transTest($paramArr=null) { /** 1. 트랜잭션 시작 선언 */ $this->transStart(); foreach ( $paramArr as $param) { $this->query("insertTestTable", array('param'=>$param)); // insert 쿼리 수행 } // 업데이트의 경우는 대상 ROW 가 없어도 transaction 은 성공 (쿼리는 성공했기 때문) $this->query("updateTestTable"); /** 2. 트랜잭션 종료 선언 (이 때 commit / rollback 이 이루어진다) */ $result = $this->transEnd(); // $this->transComplete(); 로도 활용 가능하다 /** 3. 결과 확인 및 분기처리 */ if ( $result === true ) { /** 트랜잭션 성공 케이스 */ } else { /** 트랜잭션 실패 케이스 */ } } } ==== 수동 트랜잭션 ==== 수동 트랜잭션이란 commit, rollback 을 프레임웍이 아닌 개발자가 소스 상에서 직접 정의하여 결정하는 트랜잭션 방식이다. === 사용 예제 === /** * KTK_Model 을 extends한 model에서만 공용 트랜잭션 활용 가능 * controller 등에서 트랜잭션 사용 금지 */ class Prototype_model extends KTK_Model { /** * 매뉴얼 트랜잭션 테스트 method */ function transTest($paramArr=null) { /** 1. 매뉴얼 트랜잭션 시작 선언 */ $this->manualTransStart(); foreach ( $paramArr as $param) { $this->query("insertTestTable", array('param'=>$param)); // insert 쿼리 수행 } $this->query("updateTestTable"); /** 2. 결과 확인 */ $result = $this->getTransStatus(); // 해당 호출을 통해 자동 트랜잭션과 같은 조건 판단이 가능하다, 그러나 매뉴얼인 만큼 UPDATE ROW수 혹은 기타 조건을 통한 분기 처리가 가능하다. if ( $result === true ) { /** 트랜잭션 성공 케이스 */ // 앞의 null은 datasource name 이다, null일 경우 default $this->transEnd(null, true); // $this->transCommit(); 과 동일 } else { /** 트랜잭션 실패 케이스 */ // 앞의 null은 datasource name 이다, null일 경우 default $this->transEnd(null, false); // $this->transRollback(); 과 동일 } } } ===== 주의사항 ===== ==== 트랜잭션의 유지 속성 ==== * 트랜잭션은 동일한 DB Pool에서만 작동이 됩니다. * CI환경에서는 $this->load->database(DB NAME, TRUE) 가 고유의 DB Pool을 얻는 행동이며, 동일한 DB NAME을 사용한다 하더라도 각각 해당 명령어를 통해 DB 객체를 얻었을 경우 서로 다른 DB Pool이 됩니다. * 본 프레임웍에서는 QueryParser 및 KTK_Model 의 지원으로 인해 $this->load->database 명령어를 사용할 필요가 없으며 하나의 Model내에서는 동일한 DB NAME일 경우 무조건 동일한 DB Pool로 관리되도록 설계되어 있습니다. * 즉 트랜잭션은 동일한 Model내에서는 유지가 될 수 있습니다. ($this->functionName(...) 방식으로 호출했을 경우) * 주의할 사항은 다른 Model을 객체로 호출하여 Function을 호출할 경우에는 서로 다른 Model이므로 transaction이 상호 유지되지 않습니다. * 또한, 동일 Model의 transaction 구간 내에서라도 DB NAME이 다를 경우 서로 다른 DB Pool이기에 transaction이 공유되지 않습니다. ==== 여러 Model 에서 트랜잭션을 유지하는 방법 ==== * Model에서 Model을 호출하는 경우에는 아래와 같이 DB Pool을 동기화 할 수 있습니다. /** * DB Pool을 보유하고 있는 모델에서 신규 생성된 모델로 DB Pool 동기화 * $this : DB Pool을 보유하고 있는 Model의 인스턴스 * $insTargetModel :DB Pool을 받을 Model의 인스턴스 */ $this->linkDBPoolTo($insTargetModel); * 주의사항 * DB Pool을 받을 인스턴스의 기존 DB Pool은 삭제됩니다. * 두 개의 DB Pool이 동기화(by reference)되기 때문에 한 쪽에서 transaction commit 혹은 rollback을 하면 다른 model의 transaction 또한 영향을 받습니다. * 즉 한 모델에서 transaction을 시작했을 경우, 해당 명령어로 DB Pool이 연결된 모델에서는 transaction을 시작할 필요가 없습니다. * 해당 기능은 테스트가 필요합니다. 해당 기능으로 모델간 transaction을 유지하실 때에는 충분한 테스트를 부탁드리며, 문제가 발생하거나 의도대로 작동하지 않을 경우 문서 작성자에게 문의 부탁드립니다. ==== 트랜잭션이 유지되지 않는 경우 ==== * Model에서 transaction start(혹은 begin) 을 하지 않은 경우 * 서로 다른 DB Name 을 사용한 query 수행일 경우 * Model 내에서 ($this 가 아닌) 다른 Model을 호출하여 DB Pool 연동 없이 query를 수행했을 경우 * Controller 에서 model을 여러 번 호출하는 방식으로 복수의 query를 수행하는 경우 (Controller level에서 transaction을 묶을 수 없습니다.) * transaction 을 시작한 후 transEnd 혹은 commit을 명시적으로 선언하지 않았을 경우 (자동 rollback 됩니다.)