CI 묻고 답하기

제목 ci3 트랜잭션 관련 질문
카테고리 CI 2, 3
글쓴이 마PD 작성시각 2018/02/23 10:59:25
댓글 : 14 추천 : 0 스크랩 : 0 조회수 : 19999   RSS

안녕하세요

새로 만들면서 한땀한땀 검증했던걸 트랜잭션을 활용해보려고 합니다.

그런데 생각했던것 처럼 작동하지 않는데 구글링해봐도 원인을 모르겠어서 질문드립니다.

제가 잘못 생각하고 있던걸까요? ㅜㅜ

 

point 테이블에서 point 컬럼은 마이너스를 허용하고 있지 않습니다. (UNSIGNED)

그리고 2개의 쿼리를 트랜잭션으로 묶어주고 있습니다.

1. 포인트 차감 (update)

2. 포인트 변동에 대한 로그 기록 (insert)

둘 중 하나라도 실패하면 롤백하는 동작을 원하고 있구요.

 

$point 변수에는 -2000 이 들어가 있습니다.

DB에는 0 으로 되어 있으니 실제 쿼리문은 0에서 -2000 을 시도하고 있고 곧장 mysql에 입력하면 오류가 나옵니다.

 

 

$query = "UPDATE `Point` SET `point` = `point` + ".$point." WHERE `id` = '".$id."' limit 1";

            $this->db->trans_begin(); // 트랜잭션 시작

            $this->db->query($query);
            $this->db->insert('PointLog', $data);

            $this->db->trans_complete(); // 트랜잭션 종료

            if ($this->db->trans_status() === FALSE)
            {
                $this->db->trans_rollback();
                return false;
            }
            else
            {
                $this->db->trans_commit();
                return true;
            }

 

 

수동말고 다른 방식으로도 해봤으나 마찬가지로 성공 처리가 되어버립니다 --;;;

포인트는 마이너스가 아닌 0 으로 처리 되며, 로그 기록에는 차감처리한 것으로 나옵니다.

프로파일로 나오는 쿼리문을 복붙하여 바로 DB에 넣어보니 오류가 나옵니다.

제가 트랜젝션을 잘못 이해하고 있는걸까요? ㅜㅜ 아니면 UNSIGNED 으로 된 컬럼에 마이너스 업데이트하는건 실패로 치지 않는걸까요...?

 다음글 두 개 이상의 rewrite 설정은 어떻게 해야할까요? (1)
 이전글 하나도 안건드렸는데, welcome 페이지가 404에러... (12)

댓글

마PD / 2018/02/23 11:03:18 / 추천 0
DB는 mysql 사용하며 innodb 입니다
kaido / 2018/02/23 11:04:29 / 추천 0

우선 문법부터 맞추도록 해요.

수동 실행 방법은 이렇습니다.

http://www.ciboard.co.kr/user_guide/kr/database/transactions.html

$this->db->trans_begin();

$this->db->query('AN SQL QUERY...');
$this->db->query('ANOTHER QUERY...');
$this->db->query('AND YET ANOTHER QUERY...');

if ($this->db->trans_status() === FALSE)
{
        $this->db->trans_rollback();
}
else
{
        $this->db->trans_commit();
}

 

 

더불어서 update문도 액티브레코드 스타일로 작성 하시는게 좋을것 같습니다.

단순히 보면 point + - 2000,  이렇게 표시되는거라서...

$this->db->set("point",-2000);

$this->db->where("id", $id);

$this->db->update("Point");

 

간결한 쿼리문 조건은 액티브레코드로 set 과 where 조건 추가로 쉽게 추가 삭제가 되어서 query 작성하시는것보다 편합니다.

마PD / 2018/02/23 11:22:08 / 추천 0

@kaido

답변 감사합니다.

복사해주신 예제를 메뉴얼에서 보고 복붙해서 넣은 뒤 제가 필요에 맞게 쿼리문이랑 return 만 넣은건데 잘못 사용하고 있는걸까요??

액티브레코드로 작성하고 싶었는데 포인트가 마이너스일수도, 플러스일수도 있어서 하나로 처리하는게 안되더라구요.

 

그래서 함수를 나눌까 하다가 저렇게 합쳐둔 상태이긴 합니다... 함수를 나누더라도 액티브레코드로 맞추는게 나을까요? 음...

 

insert의 경우 위쪽에서 $data 배열에 값들을 셋팅해놓고 있습니다.

마PD / 2018/02/23 11:30:59 / 추천 0
아............멍청하게 수정하다 말아서 컴플릿트를 하고 있었네요...설마 저거 때문인가
마PD / 2018/02/23 11:32:20 / 추천 0
            $this->db->trans_begin();

            $this->db->insert('PointLog', $data);
            $this->db->set('point', $point);
            $this->db->where('cid', $cid);
            $this->db->update('Point');

            if ($this->db->trans_status() === FALSE)
            {
                $this->db->trans_rollback();
                return false;
            }
            else
            {
                $this->db->trans_commit();
                return true;
            }

 

이렇게 수정하였으나 역시나 아직도 성공으로 처리가 되네요.

마PD / 2018/02/23 11:34:48 / 추천 0

update는 원래 쿼리문으로 되돌렸습니다.

`point` = `point` + $point 형태를 써야하는데 구글링 해보니 이렇게 하는 방법은 없다...라는 내용 밖에 없어서요.

현재 값에서 +- 시키는게 액티브레코드로 가능한가요 ?

한대승(불의회상) / 2018/02/23 12:25:15 / 추천 0
$this->db->set('point', 'point + ' . $point, false);

로 테스트 해보세요.

트랜젝션은 굳이 수동으로 하지 않아도 됩니다.

트랜잭션 성공 여부에 따라 값을 리턴하고 싶다면 아래처럼 해보세요.

$this->db->trans_start();
뭔지 한다.
$this->db->trans_complete();

if ($this->db->trans_status() === FALSE)
{
        에러에 관련된 뭔가 한다 없으면 말고...
        return false;
} else {
        return true;
}

 

마PD / 2018/02/23 14:17:29 / 추천 0

@불의회상

감사합니다. 액티브레코드는 저런 방법이 있었군요! 해보니 잘 작동해서 적용시켰습니다.

그러나 트랜잭션은 여전히 안되네요 ㅜㅜ

마PD / 2018/02/23 14:22:40 / 추천 0
        $this->db->trans_start();

        $this->db->set('point', 'point + ' . $point, false);
        $this->db->where('cid', $cid);
        $this->db->update('Point');

        $this->db->insert('PointLog', $data);

        $this->db->trans_complete();

        if ($this->db->trans_status() === FALSE)
        {
            $this->db->trans_rollback();
            return false;

        }
        else
        {
            $this->db->trans_commit();
            return true;
        }

코드는 이렇게 수정했습니다.

디비에는 0 이라는 값을 넣고,

$point 에는 -2550 이라는 값을 넣고 테스트를 돌리자 잘 작동(true 반환) 합니다. ㅜ.ㅜ

 

프로파일에 나오는 쿼리문은 다음과 같이 나옵니다.

UPDATE `Point` SET point = point + -2550
WHERE `cid` = '3' 

INSERT INTO `PointLog` (`cid`, `pt_time`, `pt_point`, `pt_used_id`, `pt_used_type`, `pt_memo`) VALUES ('3', '2018-02-23 14:49:29', '-2550', 11, 'alim', '테스트 차감') 

 

실패해야 맞는 update 문을 phpmyadmin 에서 직접 쿼리로 넣으면 다음과 같이 오류가 납니다.

#1264 - Out of range value for column 'point' at row 1

이걸 왜 오류로 안볼까요 --;;

마PD / 2018/02/23 15:50:53 / 추천 0
        $this->db->query("set autocommit=0");
        $this->db->query("begin");

        $this->db->set('point', 'point + ' . $point, false);
        $this->db->where('cid', $cid);
        $this->db->update('Point');
        $r1 = $this->db->affected_rows();

        $this->db->insert('PointLog', $data);
        $r2 = $this->db->affected_rows();

        if($r1 < 1 || $r2 < 1)
        {
            $this->db->query("rollback");
            $result['status'] = false;
            $result['data'] = "db 수정 실패";
            return $result;
        }
        else
        {
            $this->db->query("commit");
            $result['status'] = true;
            $result['data'] = "성공";
            return $result;
        }

 

결국 이렇게 수정하였습니다.

돌려보니 원하던 대로 작동하네요. (update 성공시 커밋, update 실패할 경우 롤백)

뭔가 겁~~~~나 찝찝하지만 일단 이렇게 하긴 했습니다 --;

/ 2018/02/23 17:01:02 / 추천 0

의문 1) point 컬럼의 경우 마이너스 값을 안넣게 범위를 UNSIGNED 넣어놓고 마이너스 값을 넣으려고 하는가?

의문 2) point가 - 값일때 return false 하고 싶은건가?

마PD / 2018/02/26 10:43:06 / 추천 0

@닉

1. 포인트 컬럼이 마이너스 값을 허용하고 있지 않으면서 실제 입력값 중 마이너스가 존재합니다.

흔히 생각하는 포인트 시스템이고, 늘었다 줄었다 하지만 음수로 내려가지는 않는거죠

2. 앞에 1번과 같습니다. 보유 포인트가 100점인데 -200점을 시도하면 쿼리문을 실패하고 리턴 값은 false 가 나오길 원하는거죠

/ 2018/02/28 04:40:30 / 추천 0

마PD 그런 의도시군요.

아마도 1번째 업데이트 구문에서 가감해서 -값이 되더라도 0으로 입력되도록 하는 mysql 옵션이 있을거에요. 그걸 온 오프하냐에 따라 에러가 나도록 하는게 있고 그냥 0으로 입력되도록 하는 옵션이 있던걸로 기억하는데 그거때문일거에요. 0으로 들어가니 당연히 에러가 발생하지 발생하지 않고 따라서 트랜젝션은 커밋되는 거죠.. 아마도.. safe mode였던가 했던거 같은데.. 맞을걸요? 아니면 댓글 부탁해요.

 

 

k / 2021/11/10 17:47:00 / 추천 0
저도 마PD님이랑 trans_status() 작동하는 기준을 몰라 affected_rows 로 해결하는데 너무 찝찝해요