C++Builder ADO Programming (6) - Dive to TADOCommand 우리의레밍은지난강의까지 ADO에대한개괄적인사항과 Connection 객체에대해서알아보았다. 앞으로의진행에기본적인내용이긴하지만그래도열심히공부를한녀석이라면 에이, 이게뭐야너무약해 ~! 라고지껄일것이다. 그것이야말로좋은태도라고생각한다. 사실그것은앞으로다가올온갖고난과시련에대비하는든든한마지막비상식량일것이다. 자잡설은그만하고 Command 객체에 Dive 하자. Connection 객체의장에서 Connection 객체만으로도데이터원본에대해명령을수행할수있었다는것을기억하길바란다. 예를들면 Connection 객체만으로도저장프로시저를호출할수있었으며저장프로시저들과인자들을주고받을수도있었다. 뿐만아니라테이블과 View를통해데이터셋을열어가져올수도있었다. 그러나 Command 객체는 명령수행 에특화된객체이기때문에다른객체들보다훨씬더융통성있고확장된방식으로명령을수행하게해준다. 여기서의명령이란데이터원본에대해직접 SQL 질의문이나저장프로시저를수행하거나테이블과 View와같은데이터베이스서버객체를이용하는것일수도있다. ADO 객체모델의문서에서든 VCL화되어있는 TADOCommand를살펴보더라도 Command 객체는 Connection 객체보다메소드나속성이적다는점을알수있다. Event는아예없다. 이는 Command 객체가하나의작업 --- 데이터원본에대해어떠한명령만을수행하는작업 --- 만을위한것이기때문이다. 미리맛보기를계속하자면저장프로시저의경우 Connection 객체에서의저장프로시저호출과비교해서 - -- 이전의강의에서인자가필요한저장프로시저를조잡한스트링조작으로호출한것을기억하라! 물론인자가필요없는저장프로시저는그냥호출하면되겠지만 --- Command 객체를이용하면동적으로인자들을얻을수있으며그것들을클라이언트에게보낼수있다. 이를통해서클라이언트가그인자들을동적으로 --- 인자들의개수나데이터형을미리알아야할필요가없다 --- 표시하고, 사용자로부터값들을받아서그값들을인자에넣는등의작업이가능하다. 또 Command 객체에연결된 Connection 객체의메소드형태로어떤명령이나저장프로시저들도호출할수있다. 이번 Command 객체의강의에서다룰내용은다음과같다. Command 객체와사용법 오늘먹을것 = ㅅ =;; Parameters 컬렉션. Parameter 객체 다양한저장프로시저와 Command 객체에서의사용법 역시 Connection 객체때와마찬가지로각각의내용을다루는장에서그에관련된메소드와속성들을함께살펴보자. Command 객체 말그대로이다. 어떠한명령을뜻하는객체이다. Command 객체는데이터원본에대해어떠한명령을수행하거나데이터셋이나데이터원본이반환하는값을받을때사용한다. 간단히말해서이객체는데이터원본에대해지시할수있는어떠한하나의명령을대표한다고할수있다. 단순하게명령수행의측면에서만본다면 Command 객체는 Connection 객체가할수있는일을모두할수있다. Connection 객체가 Transaction을관리하고 Errors 컬렉션을가지고있는반면 Command 객체는 Parameters 컬렉션을가지고있다. --- 첫번째강의에서객체모델에대한그림을기억하길바란다. 이 Parameters 컬렉션은다음강의에서살펴보겠지만데이터원본에있는저장프로시저를사용할때매우큰역할을한다. 저장프로시저가출력인자를사용하여클라이언트에게값들을돌려주는경우 Connection 객체로는그값들을얻을수없다. 그러나 Command 객체를사용하면 Parameters 컬렉션을통해서변경된인자들의값을주고받을수있으며또한저장프로시저의반환값도받을수있다. 미리짧게언급하는내용이지만나중에이강의의한
Chapter 를차지할만큼중요한단절된레코드셋이란개념이있는데이단절된레코드셋을생성하는데 Command 객체가사용될수있다. 소개는이정도로마치고 Main Dishes 인 Command 객체의여러속성들 과메소드들을맛있게먹어주기로하자 ~ 냠냠냠 ~ 명령의수행 Command 객체의명령의수행에직접적인관련이있는속성엔 CommandText, CommandType, CommandTimeout, Prepared 속성과 Execute 메소드가있다. 자하나씩해치우자. CommandText 속성이속성은 Connection 객체를다룰때접한속성이다. Command 객체에도그와동일한속성이있으며수행할명령을뜻하는문자열을담는다. 그문자열은역시 SQL 문장일수도있고저장프로시저이름이나테이블, View의이름일수도있으며아니면데이터공급자만의어떠한명령어일수도있다. 기본값은정해져있지않으며이속성에담긴명령의종류는 CommandType 속성에반영된다. Object Inspector의 버튼을누르면다음과같은 CommandText Editor 창이뜬다. 이창이뜨는이유는이다음에설명할 CommandType 속성의기본값이 cmdtext로설정되어있기때문이다. 그리고그전에 Connection 객체의인스턴스를하나생성하고 --- 폼이나데이터모듈에 TADOConnection 객체를떨어뜨려서 --- 연결하고자하는데이터원본에대한정보를가진 ConnectionString을생성한후 Command 객체의인스턴스의 Connection 속성에연결하는것이선행되어야
한다. (Command 객체자체의 ConnectionString 속성으로연결정보를생성해도되지만별로추천하고싶지않다 ) 연결정보가맞다면위의그림처럼연결정보에해당하는스키마에속하는테이블들과그테이블에해당하는필드들이보이고각각창의아래에있는버튼클릭으로오른쪽 SQL 편집창에더하거나직접 SQL 문을작성, 편집할수있다. 만약연결정보가없거나활성연결이없고또연결정보가잘못된경우, 테이블들과필드들창에아무것도나타나지않는다. 단 SQL 문은입력가능하다. 이 CommandText Editor 창은 CommandType 속성의값이 cmdtext 이거나 cmdunknown일때뜨며아래의그림과같이 cmdtable일때는이창대신테이블들의리스트를 cmdstoredproc일때는저장프로시저들의리스트를보여준다. 앞으로 CommandType 속성에서자세히알아보겠지만이값중에 cmdtabledirect와 cmdfile는될수있으면 Command 객체와함께사용하지말기를추천한다. 에러를일으키는수도있다. cmdtabledirect는모든공급자들이지원하지는않는다. cmdtabledirect대신 cmdtable을사용하길추천한다. 위값들은 Command 객체보다 TCustomADODataSet 의후손클래스인 ADO DataSet들을위한값이다. 여태껏줄기차게설명하였으나이런방법보다는다음의방법을추천하고싶다. 뭐괜찮다, 허무의극복은인생의일반적이면서도지극히개인적이고고유한, 숙명적인과제중에하나다. = ㅅ =;; 여러분은이전의 ConnectionString을다룬강의에서무대뽀통박레밍을기억할것이다. 통박으로들이미는아주무서운녀석이었는데앞의내용도이녀석이한대로 Connection 객체에 Connection 속성만연결하고나머지는코드를통해들이미는것이낫다. 손가락이아프다고? Code Complete 기능이느리다고? 필자와레밍이만세를부르고박수를쳐줄것이다! = ㅅ =;; 아래의소스는위에서설명한예이다. 이속성을사용하는구문으로 SQL 문, 그리고저장프로시저를집어 넣고그것이각각 SQL 문과저장프로시저임을데이터원본에알려주는예이다.
위의소스에서보는것같이 CommandText 속성과 CopmmandType 속성을이용하여 Command 객체를실 행시킴으로데이터셋을직접가져올수있고저장프로시저를실행시킬수도있다. 자그럼 CommandType 속성에대해알아보자. CommandType 속성앞에서잠깐설명한대로이속성은데이터원본에게보낼명령의종류를뜻한다. TCommandType의열거형값으로다음의값을가진다. Connection 객체의 Recordset을반환하는 Execute 메소드의 2 번째인자형이기도하다. CommandType 의미 cmdtext 기본값으로데이터원본에대해한문장을실행한다. 이값이설정되면 CommandText 속성엔주로 SQL 문이사용되며인자를가지지않는저장프로시저나 View등도사용할수있다. cmdtable CommandText 값이테이블의이름이된다. 그리고그테이블을연다. cmdstoredproc CommandText 값이저장프로시저의이름이된다. 그리고그저장프로시저를수행한다. cmdunknown CommandText 값에있는명령종류를알수없다. cmdtabledirect CommandText 값이테이블의이름이된다. 그테이블을직접연다. 단모든공급자들이지원하지는않는다. 주로이값은 Command 객체를위한것이기보다 ADODataSet들을위한 CommandType 이다. cmdfile CommandText 값이저장된레코드셋파일이름이된다. 역시위의 cmdtabledirect와마찬가지로 Command 객체에서사용되기보다 ADODataSet들을위한 CommandType 이다. Execute 메소드 Connection 객체의 Execute 메소드와마찬가지로 Command 객체의 Execute 메소드역시데이터원본에대해명령을수행하고데이터를얻는수단을제공한다. 그러나 Connection 객체와는달리 Command 객체를이용하면데이터원본에인자들을전달할수있다. 다음은 Execute 메소드의원형이며 3가지의다른원형이있는것을볼수있다.
첫번째아무인자도가지지않는메소드는위의예제에서보았듯이단순한 SQL 문과테이블들, 넘겨줄인자가없거나 Parameters 컬렉션으로인자설정이끝난저장프로시저의호출등일반적으로사용되는형태이다. 나머지메소드는인자들을 OleVariant형의배열형태로넘겨줄때사용된다. 2번째와 3번째메소드의차이는명령의수행결과그명령이적용된레코드의개수를정수형의 RecordAffected 인자에게돌려주는지의여부이다. 위는이전의 Connection 객체의강의때다루었던저자들을추가하는저장프로시저다. 역시동일하게데이터원본인 SQL 서버에위와같은저장프로시저가있을때 Command 객체의 Execute 메소드로프로시저를호출하는방법을알아보자. 이전의 Connection 객체로인자를가지고있는저장프로시저를호출할때는 CommandType 값이 cmdstoredproc 이아닌 cmdtext 값으로설정한뒤 CommandText 속성의값인명령문스트링과인자들을스트링조작으로건네주고 Query Analyzer나 isql 같은 SQL 문실행에디터에서저장프로시저를호출하는식으로저장프로시저앞에 EXEC 이라는명령어를붙여실행시켰음을보았을것이다. 사실인자가필요없는저장프로시저는거의쓸모가없으므로 --- 그리고대부분의어플리케이션은조건과인자를갖춘데이터조작이많이쓰인다 --- 인자가필요한저장프로시저를두객체를통해호출하는방법을각각비교해보고알아두자. --- 사실 Command 객체가필요없는경우어플리케이션내에서실행파일의크기도크기거니와꼭쓸필요가없다. 양쪽을알아두면그런경우에유용할것이다. 같은맥락에서 ADO 탭에는저장프로시저만을전문적으로다루는 TCustomADODataSet의후손클래스인 TADOSoredProc Component가있는데나중에살펴보도록하자. 그러나필자의경우 Command 객체를선호한다.
Execute 메소드첫번째형은 CommandText 속성과 CommandType 속성에서알아보았으므로 3번째메소드형을다루어보았다. 2번째메소드는 3번째메소드의첫번째인자를생략하면되므로 3번째메소드와거의같다고생각하면된다. 굳이적용된레코드의개수를알고싶지않으면인자가있고그것을간단한방식으로넘겨줄경우의저장프로시저를호출할경우 2번째메소드형을사용하는것을추천한다. 여기서중요하게봐두어야하는것은 2번째와 3번째 Execute 메소드의 OleVariant 형의인자인 Parameters이다. 이인자는데이터원본에있는저장프로시저를호출할때인자들을건네주는역할을하는데저장프로시저가원하는인자들의타입이각각다르기때문에항상 Variant 형의배열이되어야한다. 다행히도 VCL의 Variant 형과클래스는아주막강하므로간단히해결할수있다. 위의예제소스도그것을보여주고있는데만약인자가필요하지않다면 --- 그럴경우는거의없을것이다 --- Connection 객체의 OpenSchema 메소드를다룰때처럼 EmptyParam을넘겨준다. 인자들의 Variant 배열을생성해서값을채우고 2, 3 번째 Execute 메소드를호출하는방법은위에서도언급했듯이 Command 객체의 Parameters 컬렉션을이용해서인자들을설정한뒤첫번째 Execute 메소드를호출하는방법과같다. 그러나 Parameters 인자가 Parameters 컬렉션보다우선한다. 즉 Parameters 인자를지정한경우인자에지정된값들은 Parameters 컬렉션에있는인자값들보다우선한다. 다음필자의개농장소스의일부를보면저장프로시저가아니라 CommandType 속성을 cmdtext로설정한후 CommandText 속성에참친근하고도즐겁고익숙한 TQuery Component의 SQL 속성에서쓰던인자달린 SQL 문을날리는것을볼수있다. 그러나필자는이런방식을좋아하지는않으며여러분은가능성만을보기바란다.
특별한것은없었다. 단지 CommandType 속성이 cmdtext 로바뀌고 CommandText 속성에인자달린 SQL 문이들어가있을뿐이다. 인자달린 SQL 문도 Execute 메소드를이용하여인자값을전달해서명령을실행 시킬수있다는것만알아두자. View 역시 Command 객체로관련 RecordSet 들을가져올수있다. SQL Server 나라에다음과같은 View 가 있다고하자. 이 View 는이름그대로작가당책이몇권이나팔렸는지에대한총합을알려주며데이터를불 러들여스트링조작을하는고통스럽고비효율적이며쓸데없는코드가들어가는일을덜어준다.
자그럼이 View 를 Command 객체로가져오자. Connection 객체때와마찬가지로비교적간단하다. View 의단점중의하나는조건을지정할수없다는것이다. 위의 View도조건이없는데 --- Where 절이없는것을볼수있다 --- 가령책이총 50권이상팔린저자들만을조회하는경우가그러하다. 이런경우조건에해당하는인자값을건네받고데이터셋을돌려주는저장프로시저나사용자정의함수를사용할수있다. 그리고그조건은언제나상황에맞게변화하므로인자값으로건네주는것이해결책이다. 나머지자세한사항은 Command 객체의 Parameters 컬렉션에대해서다룰때알아보자. ExecuteOptions 속성이속성은 Connection 객체의 Execute 메소드를다룰때접해본속성이다. TExecuteOptions 열거형으로아래의값을가진다. Command 객체가수행하는명령의실행속성을정의한다. 항상 Execute 메소드를실행하기전에설정한다. Execute Options 의미 eoasyncexecute 명령이비동기적으로실행된다. eoasyncfetch 데이터를비동기적으로가져온다. eoasyncfetchnonblocking 데이터를비동기적, 비블로킹방식으로가져온다. eoexecutenorecords 데이터를돌려주지않는명령에쓰인다. 전반적인내용은 Connection 객체의 Execute 메소드를살펴볼때다루었던내용과동일하다. ADO가골때리는것중하나가명령을수행할때마다 Recordset을생성하는데 --- 데이터질의가아닌명령에대해서는빈데이터셋을만든다 --- 이것은서버가비효율적이고쓸데없는것에시간과자원을소비하는결과를낳는다는것이다. 데이터셋을돌려받을필요가없는명령들에한해서반드시이속성에 4번째인자인 eoexecutenorecords 값을추가해줘야한다. 위에서설명한소스들을참고하길바란다. CommandTimeOut 속성이속성역시 Connection 객체의해당속성과마찬가지로데이터원본에보낼하나의명령이수행될수있는제한시간을뜻한다. 기본값은 30 초이다. 이속성은해당 Command 객체와연결된 Connection 객체의 ConnectionTimeOut 속성을물려받지않으며그값을덮어쓰지도않는다. Connection 객체의 CommandTimeOut 속성은그 Connection 객체의 Execute 메소드에만적용되는것이며 Command 객체의 CommandTimeOut 속성은 Command 객체자체의 Execute 메소드에만적용되는것일뿐이다. 그리고이속성을 0으로설정하는것은명령을수행할수있는시간제한을두지않는다는것이다. 그러나이속성의설정과는다르게명령의시간제한이데이터원본자체의설정으로되어있는경우를볼수있다. 다음은 SQL Server를데이터원본으로할때명령의시간제한을설정하는창이다.
데이터베이스이름에서마우스오른쪽클릭하여등록정보를선택하면된다. 이와같이백엔드자체의설정 이있을때는그것에따른다. 그러나필자의경험으로제한시간을두는것이낫다. 계류중인작업이나많은 시간을잡아먹는작업은분명서버에부하를주기때문이다. Prepared 속성이속성은 BDE를사용한데이터베이스프로그래밍에서많이접해본아주친근하고즐거운속성이다. ADO의 Command 객체도이속성을가지고있는데이속성은데이터원본에대해어떠한명령을수행하기전에그명령을미리컴파일해둘것인지의여부를결정한다. CommandType이 cmdstoredproc이아닌경우 --- Command 객체가수행하는명령이저장프로시저를호출하는명령이아닐경우 --- 명령을미리컴파일해두는것이수행성능에도움이될수있다. 물론명령이처음수행될때는추가적인부담이생기지만그이후부터컴파일된버전의명령이수행되는것이므로첫번째보다훨씬더빠르게수행된다. 이는위의인자가달린 SQL 문을 Command 객체를통해날리는것을다룬필자의소스에서처럼동일한명령을여러번수행하는경우특히더유용하다. States 속성 이속성은읽기전용으로 Command 객체의현재상태를뜻한다. 이속성이돌려줄수있는값들은 Connection 객체의 State 속성과마찬가지로 TobjectStates 열거형으로아래의값을가진다. stclosed Command 객체가닫히고데이터원본과의연결이종료되었다. StOpen Command 객체가데이터원본과연결되어있음. stconnecting Command 객체가연결중임. stexecuting Command 객체가명령을실행중임. stfetching Command 객체가데이터를가져오는중임. 마지막두값인 stexecuting 과 stfetching 은비동기적명령이수행되는도중에만나타난다. 이속성을이용
하면 Command 객체가데이터원본에아직연결되어있는지를검사할수있다. 만일연결이끊어졌다면 Connection 속성을다시설정한후작업을개시해야할것이다. Cancel 메소드 Cancel 메소드는 Command 객체의비동기적작업에관련된것이다. 일반적으로비동기적작업이란명령이나행위, 조작등을수행한후에그에대한반응이즉시돌아오는동기적작업과달리그반응이언제원래수행자에게돌아올지모르는작업을말한다. 진행중인비동기적작업이없는상황에서이메소드를호출하면런타임에러가발생한다. Connection 객체의 Cancel 메소드와마찬가지로명령을비동기적으로수행시킨명령이나조작들을 States 속성을이용하여취소시킬때주로사용할수있다. 다음의의사코드를보자. 이코드는명령을비동기적으로실행시킬경우그에해당하는이벤트핸들러에해당하는내용일것이다. 다 음은비동기적으로실행중인 Command 객체의상태를알아내 Cancel 메소드를사용하여그명령을취소하 는코드이다. 필자의경험으로볼때될수있으면데이터를조회하는명령은비동기적으로실행시키지말것을추천 한다. 주어플리케이션과별도의스레드에서데이터조작이나조회등과거리가먼모니터링이나관리명령등 을날려볼것을추천한다. 비동기적작업은상태유지가편한클라이언트 / 서버어플리케이션에서쓰이는것이일반적이다. 웹기반 어플리케이션의경우비동기적작업이그다지실용적이지는않다. 왜냐하면여러분도다아시다시피웹은 근본적으로상태가없는환경이기때문이다.
이번강의는여기까지이다. Dive를해보았는데뭐처음은시원하고재미있었지만나중은 Connection 객체를다룰때의내용과비슷한부분이많아서재미없었다. Command 객체의속성과메소드는이것으로마치고다음강의에서 Parameters 컬렉션과 Parameter 객체에대해알아보도록하자. 다음에는해수욕을그만하고잠수도한번해보자. 아직도우리를기다리는예쁜물고기와조개들은많이있다. = ㅅ =;; Mortalpain