적용 대상:SQL Server
Azure SQL Database
이 퀵스타트에서는 Windows, Linux, macOS에서 C++ 콘솔 애플리케이션을 구축합니다. 애플리케이션은 Microsoft ODBC Driver 18 for SQL Server를 사용하여 데이터베이스에 AdventureWorksLT 연결하고, 쿼리 매개변수를 바인딩하고, 쿼리를 실행하며, 결과 행을 읽습니다.
Prerequisites
- Microsoft ODBC Driver 18 for SQL Server. Windows, Linux, macOS용 드라이버를 설치하세요.
- C++17 컴파일러와 플랫폼 ODBC 개발 파일:
- Windows에서는 Visual Studio 2022 또는 C++ 데스크톱 개발 워크로드와 함께 Visual Studio 2022 빌드 도구를 설치하세요. Windows SDK는 ODBC 헤더와
odbc32.lib를 제공합니다. - 리눅스에서는 C++ 컴파일러와 배포판용 unixODBC 개발 패키지를 설치하세요. 패키지는 ODBC 헤더와
libodbc를 제공합니다. - macOS에서는 Xcode 명령줄 도구와 Homebrew에서 유닉스ODBC를 설치하세요.
- Windows에서는 Visual Studio 2022 또는 C++ 데스크톱 개발 워크로드와 함께 Visual Studio 2022 빌드 도구를 설치하세요. Windows SDK는 ODBC 헤더와
- 샘플 데이터를 포함하는
AdventureWorksLTAzure SQL Database 또는 SQL Server 내 데이터베이스입니다. Azure SQL Database의 경우, 단일 데이터베이스를 생성할 때 샘플 데이터 소스를 선택하세요. SQL Server의 경우, AdventureWorks 샘플 데이터베이스에서 백업을AdventureWorksLT복원하세요.
운전자를 확인해
드라이버 관리자가 Microsoft ODBC Driver 18 for SQL Server를 찾을 수 있는지 확인하세요.
각 명령어는 ODBC Driver 18 for SQL Server를 나열해야 합니다. 드라이버가 목록에 없다면, 진행하기 전에 드라이버를 재설치하세요.
연결 설정
애플리케이션은 환경 변수에서 ODBC_CONNECTION_STRING 전체 연결 문자열을 읽습니다. 연결 문자열을 표시하지 않거나 명령줄 인수로 받아들이지 않습니다.
데이터베이스와 인증 방식에 맞는 Driver 18 연결 문자열을 사용하세요. 다음 SQL 인증 예시는 데이터베이스가 SQL 인증을 허용할 때 Windows, Linux, macOS에서 작동합니다:
Driver={ODBC Driver 18 for SQL Server};Server=tcp:<server>,1433;Database=<database>;UID=<user_id>;PWD=<password>;Encrypt=yes;TrustServerCertificate=no;
Microsoft Entra 인증 옵션에 대해서는 ODBC 드라이버와 함께 Microsoft Entra ID 사용하기를 참조하세요. 지원되는 모든 설정에 대해서는 DSN 및 연결 문자열 키워드와 속성을 참조하세요.
Microsoft ODBC 드라이버 18은 기본적으로 암호화를 활성화합니다. 애플리케이션의 요구사항이 명시적으로 되도록 명시 Encrypt=yes 하세요. 드라이버가 서버 인증서를 검증하도록 프로덕션 상태로 유지 TrustServerCertificate=no 하세요. 인증서는 서버 이름과 체인을 클라이언트가 신뢰하는 인증 기관과 일치해야 합니다. 구성 지침은 인증서 검증 실패를 참조하세요.
Caution
TrustServerCertificate=yes 인증서 검증을 건너뛰는 것. 클라이언트가 신뢰하는 인증서를 구성하는 동안 로컬 개발에만 사용하세요. 프로덕션 환경에서는 사용하지 마세요.
환경 변수는 연결 문자열을 셸 히스토리에 추가하지 않고 설정하세요.
VS 2022용 오픈 개발자 PowerShell. 이 명령어들을 실행한 후, 다음 프롬프트에 연결 문자열을 붙여넣으세요:
$secureConnectionString = Read-Host "ODBC connection string" -AsSecureString
$env:ODBC_CONNECTION_STRING = [System.Net.NetworkCredential]::new(
"", $secureConnectionString).Password
$secureConnectionString = $null
환경 변수는 연결 문자열을 소스 파일에 포함시키지 않지만, 프로세스와 그 자식 프로세스는 이를 읽을 수 있습니다. 운영 애플리케이션의 경우, 가능한 경우 Microsoft Entra 인증을 사용하고 런타임에 보안 저장소에서 비밀을 가져오세요.
애플리케이션 만들기
프로젝트 디렉터리를 만들고 그 디렉터리에 변경하세요:
다음 코드를 사용하여
odbc-quickstart.cpp라는 파일을 만듭니다.#ifdef _WIN32 #include <windows.h> #endif #include <sql.h> #include <sqlext.h> #include <sqltypes.h> #include <cstdlib> #include <iomanip> #include <iostream> #include <string> std::string ReadEnvironmentVariable(const char* name) { #ifdef _WIN32 char* value = nullptr; std::size_t length = 0; if (_dupenv_s(&value, &length, name) != 0 || value == nullptr) return {}; std::string result(value); std::free(value); return result; #else const char* value = std::getenv(name); return value == nullptr ? std::string{} : value; #endif } void PrintDiagnostics(SQLSMALLINT handleType, SQLHANDLE handle) { SQLCHAR state[6]; SQLINTEGER nativeError; SQLCHAR message[SQL_MAX_MESSAGE_LENGTH]; SQLSMALLINT messageLength; for (SQLSMALLINT record = 1; SQL_SUCCEEDED(SQLGetDiagRec(handleType, handle, record, state, &nativeError, message, sizeof(message), &messageLength)); ++record) { std::cerr << '[' << state << "] (" << nativeError << ") " << message << '\n'; } } bool Succeeded(SQLRETURN result, SQLSMALLINT handleType, SQLHANDLE handle) { if (SQL_SUCCEEDED(result)) return true; PrintDiagnostics(handleType, handle); return false; } struct OdbcHandles { SQLHENV environment = SQL_NULL_HENV; SQLHDBC connection = SQL_NULL_HDBC; SQLHSTMT statement = SQL_NULL_HSTMT; ~OdbcHandles() { if (statement != SQL_NULL_HSTMT) SQLFreeHandle(SQL_HANDLE_STMT, statement); if (connection != SQL_NULL_HDBC) { SQLDisconnect(connection); SQLFreeHandle(SQL_HANDLE_DBC, connection); } if (environment != SQL_NULL_HENV) SQLFreeHandle(SQL_HANDLE_ENV, environment); } }; int main() { std::string connectionString = ReadEnvironmentVariable("ODBC_CONNECTION_STRING"); if (connectionString.empty()) { std::cerr << "Set ODBC_CONNECTION_STRING before running.\n"; return 1; } OdbcHandles handles; SQLRETURN result = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &handles.environment); if (!SQL_SUCCEEDED(result)) { std::cerr << "Unable to allocate an ODBC environment handle.\n"; return 1; } result = SQLSetEnvAttr( handles.environment, SQL_ATTR_ODBC_VERSION, reinterpret_cast<SQLPOINTER>(SQL_OV_ODBC3_80), 0); if (!Succeeded(result, SQL_HANDLE_ENV, handles.environment)) return 1; result = SQLAllocHandle( SQL_HANDLE_DBC, handles.environment, &handles.connection); if (!Succeeded(result, SQL_HANDLE_ENV, handles.environment)) return 1; result = SQLDriverConnect( handles.connection, nullptr, reinterpret_cast<SQLCHAR*>(connectionString.data()), SQL_NTS, nullptr, 0, nullptr, SQL_DRIVER_NOPROMPT); if (!Succeeded(result, SQL_HANDLE_DBC, handles.connection)) return 1; result = SQLAllocHandle( SQL_HANDLE_STMT, handles.connection, &handles.statement); if (!Succeeded(result, SQL_HANDLE_DBC, handles.connection)) return 1; SQLINTEGER minimumProductId = 0; SQLLEN minimumProductIdLength = 0; result = SQLBindParameter( handles.statement, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 10, 0, &minimumProductId, 0, &minimumProductIdLength); if (!Succeeded(result, SQL_HANDLE_STMT, handles.statement)) return 1; SQLCHAR query[] = "SELECT TOP (5) ProductID, Name " "FROM SalesLT.Product " "WHERE ProductID > ? " "ORDER BY ProductID;"; result = SQLExecDirect(handles.statement, query, SQL_NTS); if (!Succeeded(result, SQL_HANDLE_STMT, handles.statement)) return 1; std::cout << "Product ID Name\n" << "---------- ----\n"; while (SQL_SUCCEEDED(result = SQLFetch(handles.statement))) { SQLINTEGER productId; SQLLEN productIdLength; SQLCHAR productName[256]; SQLLEN productNameLength; result = SQLGetData( handles.statement, 1, SQL_C_SLONG, &productId, sizeof(productId), &productIdLength); if (!Succeeded(result, SQL_HANDLE_STMT, handles.statement)) return 1; result = SQLGetData( handles.statement, 2, SQL_C_CHAR, productName, sizeof(productName), &productNameLength); if (!Succeeded(result, SQL_HANDLE_STMT, handles.statement)) return 1; std::cout << std::left << std::setw(12) << productId << productName << '\n'; } if (result != SQL_NO_DATA) { PrintDiagnostics(SQL_HANDLE_STMT, handles.statement); return 1; } return 0; }
애플리케이션은 표준 ODBC API만 사용하여 드라이버 관리자 헤더와 드라이버 관리자 라이브러리로의 링크를 포함합니다. 연결 문자열은 런타임에 Microsoft ODBC Driver 18 for SQL Server를 선택합니다.
SQL_DRIVER_NOPROMPT 구성 대화상자 열기를 막습니다 SQLDriverConnect . 연결 문자열이 불완전하면 호출은 오류를 반환하고 애플리케이션은 모든 진단 레코드를 출력합니다.
쿼리는 를 SQL Server 0 매개변수로 바인딩하고, SalesLT.Product의 처음 다섯 개 제품을 읽고, SQLGetData를 사용하여 각 제품 ID와 이름을 가져옵니다.
애플리케이션 빌드 및 실행
같은 개발자 PowerShell 창에서 애플리케이션을 컴파일하세요:
cl /std:c++17 /EHsc /W4 odbc-quickstart.cpp /link odbc32.lib애플리케이션을 실행합니다.
.\odbc-quickstart.exe
애플리케이션의 표준 출력은 다음과 같습니다:
Product ID Name
---------- ----
680 HL Road Frame - Black, 58
706 HL Road Frame - Red, 58
707 Sport-100 Helmet, Red
708 Sport-100 Helmet, Black
709 Mountain Bike Socks, M
끝나면 연결 문자열을 지우세요.