LOGIN • JOININ

SQL-SIMPLE QUERY (1)

[Tutorials/[Server] 4. Query classes/Tutorial_Query01_SQL-Simple(1)]



1... ICGQuery와 ICGQuerier

ICGQuerier는 DB 등과 같이 쿼리를 처리할 대상에 연결하여 Query를 처리해 주는 객체입니다.

ICGQuery는 요청 쿼리 내용과 쿼리 결과를 가지고 있거나 읽어 오는 객체입니다.

따라서 Querier를 통해 Query를 처리하려면 다음과 같은 처리 과정이 필요합니다.


① DBQuerier를 만들어 Start한다. 즉, DB에 접속합니다.

② DBQuery 객체를 생성해 쿼리 내용을 작성합니다.

③ DBQuery 객체로 DBQuerier에 처리를 요청합니다.

④ DBQuery가 완료되면 DBQuery 객체에서 결과를 읽어냅니다.

⑤ DBQuery 객체를 할당해제합니다.(이건 자동으로 할당해제됩니다.)



2... DBQuerier Start하기

DB를 사용하기 위해서는 먼저 ‘CGServerQueryDBClasses.h’를 Include해야 합니다.

1) 일단 DB Querier객체를 동적 할당합니다.

2) Querier에 ‘접속 문자열’을 주어 Querier를 Start합니다.

접속하고자 하는 DBMS의 형태, 주소, UserID와 Password 등등의 ‘접속 문자열’을 주어 Start합니다. 

(‘접속 문자열’ 은 Visual Studio의 ‘Add Class>>ATL>>OLEDB Consumber’ 메뉴를 사용하면 자동으로 생성도 가능합니다.)

이때 특별히 설정하지 않으면 Querier는 코어수에 비례해 적정량의 세션풀을 생성합니다.

	// @1) Queirier를 생성한다.
	g_pQuerier	 = NEW<CGServerQuery::DB::CQuerier>();

	// @2) DB에 접속한다. (MSSQL)
	auto bResult	 = g_pQuerier->Start(
		L"Provider=SQLOLEDB.1;\
		Password=XXXXXX;\
		User ID=sa;\
		Persist Security Info=True;\
		Initial Catalog=TEST;\
		Data Source=127.0.0.1;\
		Use Procedure for Prepare=1;\
		Auto Translate=True;\
		Packet Size=4096;\
		Workstation ID=TEST_HOST;\
		Use Encryption for Data=False;\
		Tag with column collation when possible=False");



3... 동기적으로 쿼리하기
// 1) 동기적 Query를 요청한다.
auto	pQuery	 = g_pQuerier->RequestQuery("SELECT * FROM Account");

// Check) Query에 실패했으면 Exception을 던집니다.
ERROR_THROW_IF(pQuery.empty(), CGException::CThrow_Failure(), );

// 2) for문을 사용해 Query결과를 차례로 읽어들인다.
for(auto& iter:*pQuery)
{
	// 3) Index로 Column값을 읽어들인다.(Column은 1부터 시작)
	auto	id			 = iter.GetValue<int64_t>(1);
	auto	isDeleted	 = iter.GetValue<VARIANT_BOOL>(2);
	auto	strName		 = iter.GetValue<WCHAR*>(3);
	auto	strPassword	 = iter.GetValue<WCHAR*>(4);
	auto	dateBirth	 = iter.GetValue<DBTIMESTAMP>(5);
	auto	fHeight		 = iter.GetValue<float>(6);
	auto	fWeight		 = iter.GetValue<double>(7);

	// 3A) Field Name으로 Column index를 얻은 다음 Colume값을 읽어들일수 있다.
	int		iIndex		 = iter.GetOrdinal("Group");
	auto	strGroup	 = iter.GetValue<WCHAR*>(iIndex);

	// 3B) Field Name으로 Colume값을 읽어낼 수 있다.
	auto	strDebut	 = iter.GetValue<WCHAR*>("dateDebut");

	// 4) 읽어낸 값을 처리한다.
	...
}

1) 동기적 쿼리를 요청합니다.( RequestQuery()함수를 사용) 동기적 쿼리는 쿼리가 완료될 때까지 함수가 블록킹됩니다.

여기서는 "SELECT * FROM Account" 문의 쿼리를 요청합니다.

2) for문을 사용해 Query결과를 차례로 읽어들입니다.

3) GetValue()함수를 사용해 현재 Row의 지정된 Column값 읽어 냅니다.

3A) Column Index뿐만 아니라 Column 이름으로도 값을 읽어 올 수 있습니다.

3B) Column 문자열을 그대로 읽어 들일 수도 있습니다.

4) 읽어낸 값을 처리합니다.



4... 비동기적으로 쿼리하기

비동기적 Query는 쿼리 요청후 쿼리가 완료되지 않더라도 바로 진행이됩니다.
따라서 비동기적으로 쿼리 완료 신호를 받아 처리를 해주어야 합니다.

이 방법은 매우 다양한 방법을 제공해 줍니다.

그 중에서도 가장 간단한 방법이 람다함수(Lambda function)을 사용하는 방법입니다.

// 1) Query를 비동기식으로 수행한다.(Lambda함수로)
g_pQuerier->PostRequestQuery("SELECT * FROM Account", 
[=](HRESULT _Result, QUERY_DYNAMIC* _pQuery)
{
	// Check) Query에 실패했으면 끝냄!
	ERROR_RETURN_IF(_Result!=S_OK, _Result, );

	// 2) Query 결과 전체를 출력한다.
	for(auto& iter:*_pQuery)
	{
		// 3) Index로 Column값을 읽어들인다.(Column은 1부터 시작)
		auto	id			 = iter.GetValue<int64_t>(1);
		auto	isDeleted	 = iter.GetValue<VARIANT_BOOL>(2);
		auto	strName		 = iter.GetValue<WCHAR*>(3);
		auto	strPassword	 = iter.GetValue<WCHAR*>(4);
		auto	dateBirth	 = iter.GetValue<DBTIMESTAMP>(5);
		auto	fHeight		 = iter.GetValue<float>(6);
		auto	fWeight		 = iter.GetValue<double>(7);

		// 3A) Field Name으로 Column index를 얻은 다음 Colume값을 읽어들일수 있다.
		int		iIndex		 = iter.GetOrdinal("Group");
		auto	strGroup	 = iter.GetValue<WCHAR*>(iIndex);

		// 3B) Field Name으로 Colume값을 읽어낼 수 있다.
		auto	strDebut	 = iter.GetValue<WCHAR*>("dateDebut");

		// 4) 읽어낸 값을 처리한다.
		...
	}

	return	S_OK;
});

1) 쿼리를 비동기적으로 수행합니다. (PostRequestQuery()함수를 사용) 

또 쿼리의 결과처리를 람다함수로 정의했습니다. 

2) 쿼리가 완료되면 비동기적으로 설정한 람다함수가 호출됩니다.

3) 결과 처리 과정은 동기식과 동일합니다. 


사실상 쿼리후 처리 방법은 동기식과 비동기식의 차이가 크게 없습니다.

RequestQuery()함수 대신 PostRequestQuery()함수를 사용하며 결과 처리를 람다 함수를 사용해 비동기적으로 처리한 다는 것만 다르며 기본적 처리방법은 동일합니다.