Stored Procedure 작성시 에러 처리 팁

Stored Procedure 작성시 에러 처리 팁

일러두기. 본문서는 기배포된 중첩 트랜잭션 처리 가이드와 함께 읽으면 좋습니다.

1. @@error 와 @@rowcount 를 이용한 에러 처리

@@error : SQL문 실행도중 어떤 이유로 에러가 발생했을 때 0 이 아닌 값으로 세팅되는 시스템 함수. 에러가 발생했다가 단 한줄이라도 다음 문장이 성공하면 0 으로 세팅됨.

@@rowcount : select, insert, delete, update, set 문이 성공한 후에 몇 행을 처리했는지 세팅되는 함수.

일반적으로 SP 안에서 에러처리는 다음과 같은 패턴으로 이루어집니다.

UPDATE DEPT SET DEPT_NM = '테스트부서' WHERE DEPT = 'AD' 

if @@error <> 0 or @@rowcount <> 1  
begin
  select -1 as result_code
  return
end


자주 저지르는 실수!

declare @result_code int , @processed_rows int

UPDATE DEPT SET DEPT_NM = '테스트부서' WHERE DEPT = 'AX'    -- 'AX'라는 부서는 존재하지 않는다고 가정. 이럴 경우 처리된 행의 개수는 0개임
 
set @processed_rows = @@rowcount
set @result_code = @@error

if @result_code <> 0 or @processed_rows <> 1
begin
  select @result_code
  return
end

위의 코드는 에러가 발생하면 @@error 와 @@rowcount 를 별도의 변수에 저장하고 에러를 처리하는 코드입니다. 그런데 위의 에러처리 루틴은 결코 실행되지 않습니다.  @result_code 를 세팅하기 전에 set @processed_rows = @@rowcount 가 성공하면서  @@error 가 0으로 되고 @result_code 에는 언제나 0 이 세팅되기 때문입니다.

그렇다면 코드를 이렇게 바꾸면 어떨까요?

declare @result_code int , @processed_rows int

UPDATE DEPT SET DEPT_NM = '테스트부서' WHERE DEPT = 'AX'  

set @result_code = @@error
set @processed_rows = @@rowcount

if @result_code <> 0 or @processed_rows <> 1
begin
  select @result_code
  return
end

update 문을 실행하자마자 @@error 를 @result_code 에 넣었으므로 정상적인 값이 들어갈 것입니다. 그러면 @@rowcount 는 어떨까요? DEPT 테이블에 AX라는 부서가 없으므로  @@rowcount 는 0 이 되어야 합니다. 하지만 실행시켜보면 @processed_rows 에 1 이 들어가 있습니다. 이게 어찌된 일일까요???

원인은 set @result_code = @@error 때문입니다. @@rowcount 는 set 문에 의해서도 영향을 받습니다. 따라서 set @result_code = @@error 가 성공하면 한 개의 데이터가 변수에 저장되었으므로 @@rowcount 는 1이 되는 것입니다.

(참고 : http://msdn2.microsoft.com/ko-kr/library/ms187316.aspx)

정확한 코드는 다음과 같습니다.

declare @result_code int , @processed_rows int

UPDATE DEPT SET DEPT_NM = '테스트부서' WHERE DEPT = 'AX'  

select @result_code = @@error , @processed_rows = @@rowcount

if @result_code <> 0 or @processed_rows <> 1
begin
  select @result_code
  return
end

select 문도 변수에 값을 저장할 수 있습니다. select 문을 이용해서 한꺼번에 값을 저장하면 정확하게 원하는 값이 저장됩니다. SQL Server 2000 은 C++ 이나 Java, C# 에서 제공되는 try ~ catch 구문을 제공하지 않는다. (2005에서는 제공합니다) 따라서 에러 발생의 소지가 있는 각 insert, delete, update 문 마다 위와 같은 에러 처리 루틴을 넣어야 합니다.

(참고 : set 문으로 변수를 저장하는 것 보다 select 로 저장하는 것이 더 느리다는 개발자의 경험사례 보고가 있었습니다. 반복 테스트가 필요하겠습니다. 테스트 후 결과를 올리도록 하겠습니다.)

2. rollback, commit 할 때는 언제나 @@trancount 를 체크하자

@@trancount : 트랜잭션의 중첩 수준을 나타내는 시스템 변수. Begin tran 문에 의해 1씩 증가하고 commit tran 에 의해 1씩 감소한다. rollback tran 을 만나면 모두 롤백하면서 어떤 값을 가지고 있더라도 0 으로 변한다.

sp를 작성할 때 데이터의 정합성을 보장하기 위해서 트랜잭션을 사용하게 됩니다. 트랜잭션을 시작하면 언제나 begin tran, commit tran의 짝이 일치해야 하는 것은 당연하지요. 즉, 트랜잭션이 중첩되어서 begin tran 을 세번하게 되면 세번 commit 이 있어야 합니다. 단 rollback 은 한번에 @@trancount 를 0 으로 만들고 rollback 하기 때문에 rollback 하기 전에 언제나 @@trancount 를 체크하면서 rollback 해야 합니다.

begin tran

INSERT INTO DEPT ( … )

if @@error <> 0 or @@rowcount <> 1
begin
  if @@trancount > 0 rollback
  select -1 as err_code
  return
end

INSERT INTO TEST_TBL ( … )

if @@error <> 0 or @@rowcount <> 1
begin
  if @@trancount > 0 rollback
  select -2 as err_code
  return
end

if @@trancount > 0 commit

rollback 이나 commit 하기 전에 @@trancount 를 체크하는 것은 sp들간에 복잡하게 호출하고 각 sp들이 자체적으로 transaction 을 사용할 때 위력을 발휘합니다. 중첩 트랜잭션 처리에 관한 사항은 기배포한 중첩 트랜잭션 처리 가이드를 참고해주세요.

Posted by maceo

08 1, 2006 07:16 08 1, 2006 07:16
, , ,
Response
No Trackback , 2 Comments
RSS :
http://merritt.co.kr/tt/rss/response/59

Trackback URL : http://merritt.co.kr/tt/trackback/59

Comments List

  1. jh 2006年 08月 04日 15時 50分 # M/D Reply Permalink

    우연히 알게되어, 가끔 들러보는 놈입니다.
    본문 내용중에
    "@@trancount : 트랜잭션의 중첩 수준을 나타내는 시스템 변수."
    위 정의는, 시스템 변수를 시스템 함수로 바꾸는게 옳습니다.

    중첩 수준이냐, 트랜잭션 수냐를 따지기 전에 말이죠 :)

    1. maceo 2006年 08月 04日 23時 28分 # M/D Permalink

      지적 감사합니다~ 고쳤습니다 ^^

Leave a comment
[로그인][오픈아이디란?]
« Previous : 1 : ... 45 : 46 : 47 : 48 : 49 : 50 : 51 : 52 : 53 : ... 74 : Next »

블로그 이미지

가늘어도 긴놈이 장땡

- maceo

Archives

Authors

  1. maceo

Calendar

«   3 2010   »
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      

Site Stats

Total hits:
170306
Today:
4
Yesterday:
46