SqlConnection 클래스를 사용해서 SQL Server 연결하기

Evan Seo·2025년 2월 24일
0

C#

목록 보기
1/1

굉장히 오랜만에 글을 작성하는 것 같다.

최근에 취뽀하고 회사를 갔더니 자바는 하지도 못하고 C#만 할 것 같다.

그래서 급하게 언어도 새로 배워야 하고 .NET 개발도 처음이라 새로 배워야 하고 MSSQL도 처음해보고 전부 처음해보는 것 투성이라 배울게 굉장히 많다.

서론은 이만하고 오늘 이해한 것을 정리 해보아야겠다.

SqlConnection으로 SQL Server에 접속하기 위한 클래스이다.

SQL 서버를 사용하려면 클라이언트 프로그램이 먼저 서버와 접속되어야 한다.

서버에 접속하려면 접속 시 사용하는 Connection String이 필요한데, 이 것은 서버명과 인증 방법, 초기 데이터베이스명 등을 지정 해주어야 한다.

//아래와 같은 식으로 서버 연결을 위한 Connection String을 사용할 수 있을 것이다.
string conn1 = "Data Source=[서버주소];Initial Catalog=[DB명]; Intergrated Security=SSPI;";
string conn2 = "Data Source=[서버주소];Initial Catalog=[DB명];User ID=[아이디];Password=[비밀번호];";

이렇게 내 데이터베이스 연결에 필요한 요소들을 갖춰줬으면 이제 SqlConnection으로 서버와 접속을 할 수 있게 된다.

SqlConnection conn = new SqlConnection(conn1);
conn.Open();

...

conn.Close();

위와 같이 SqlConnection을 이용해 클라이언트 프로그램과 서버를 연결을 시켜주고 Open(),Close()로 열어서 사용하고 닫을 수 있게 된다.


그렇다면 자주 사용하는 SQL 서버에 명령을 내리기 위한 클래스에는 어떤 것들이 있을까?

회사에서 SqlConnection 명령어 중 가장 많이 봤던 클래스는 SqlCommand와 SqlDataAdapter, SqlDataReader
이 세가지를 가장 자주 봤던 클래스인 것 같다.

SqlCommand

첫 번째로 SqlCommand, 이 클래스는 SQL서버에 어떠한 명령을 내리기 위해 사용하는 클래스이다. 이 클래스를 사용해 SQL을 읽어와서 실행한다고 이해하고 있는 중이다.

예를 들면 `SELECT * FROM Table;' 이라는 쿼리를 사용한다고 했을 경우

string sql = "SELECT * FROM Table" 
conn.Open(); 
SqlCommand cmd = new SqlCommand(sql, conn); 

이렇게 사용하게 되는데 SqlCommand(sql, conn)이 잘 이해가 안갈 수도 있다고 생각한다.

첫 번째 매개변수인 sql부분은 우리가 위에서 사용하기 위해 만들었던 string sql, 즉 쿼리가 들어가게 된다.
그래서 앞자리의 역할은 string타입의 SQL 쿼리(문장)을 문자열로 전달하는 역할을 한다.

두 번째 매개변수인 뒷자리 connSqlconnection 타입의 데이터베이스와의 연결 정보를 제공하는 객체를 넣어주어야한다.
그래서 뒷자리의 역할은 SqlCommand는 "이 conn이라는 SqlConnection 객체를 사용하여 데이터베이스에 SQL 쿼리를 실행할 수 있다~" 라고 이해하면 될 것이다.

SqlCommand에는 위에서 사용된 SqlCommand 생성자 오버로드 이외에도
빈 SqlCommand를 생성하는 SqlCommand(),
지정된 SQL 쿼리로 SqlCommand 개체를 생성하는 SqlCommand(string query),
트랜잭션을 포함하여 생성하는 SqlCommand(string query, SqlConnection connection, SqlTransaction transaction)이 있다.


SqlDataAdapter

두 번째로는 SqlDataAdapter이다. 이 클래스는 SQL Server에서 데이터를 클라이언트로 가져온 후 데이터베이스와 연결을 끊은 상태(Disconnected mode) 에서 사용할 수 있도록 도와주는 클래스이다.

쉽게 설명을 한다면 SqlDataAdapter는 데이터베이스와 클라이언트(프로그램) 사이에서 중간 역할을 한다. 그래서 데이터를 가져오고나면 데이터베이스와 연결을 끊어도 데이터 사용이 가능하다는 것이다.

그렇다면 그 데이터를 가져와서 채워놓아야하는데 그것을 위해서 주로 DataSet 또는 DataTable과 함께 사용 된다.

그렇다면 어떻게 동작할까?에 대해서 알아보도록 하자

우선 데이터를 저장할 DataTable 객체를 생성해 주도록 하고, SqlDataAdapter를 생성해 SQL을 실행해 데이터를 가져와 주도록 하겠다.

DataTable dt = new DataTable();

SqlDataAdapter da = new SqlDataAdapter(sql, conn);

이제 데이터를 가져왔으니 Fill() 메서드를 사용해서 데이터를 DataTable에 저장해주어야 한다.

da.Fill(dt)

이로써 DataTable 객체에 SqlDataAdapter로 실행하고 가져온 데이터를 저장하게 된고 Fill() 메서드를 사용하게 되면 해당 위치에서 연결이 잠깐 사용된다.

이 과정을 거치게 되면 메모리(DataTable)에 데이터를 저장하게 되어 이후 연결이 끊어진 상태가 되더라도 DataTable을 사용하여 DB 연결 없이 데이터를 활용하는 것이 가능하게 되는 것이다.

SqlConnection의 연결 중, conn.Close()을 호출하지 않고 안전하게 사용하고 싶다면 using을 사용하여 해당 블록 안에서만 연결이 유지되고 Fill이 끝나면 자동으로 닫히게도 만들 수 있다.
! using을 사용하면 이벤트가 끝날 때 자동으로 연결이 닫히므로 불필요한 연결 유지 문제를 방지할 수 있다.

이후에는 DataTable인 dt를 가지고 저장된 테이블의 데이터를 활용해서 사용할 수 있다.

==========================================================================================================

if(dt.Rows.Count > 0)
{
	this.tableNumb = dt.Rows[0]["컬럼명"].ToString(); //"컬럼명" 컬럼의 0번째 인덱스의 값을 문자열로 가져온다.
}

==========================================================================================================

foreach(DataRow row in dt.Rows)
{
	this.comboBox1.Items.Add(row["컬럼명"].ToString();
}

==========================================================================================================

결론적으로 SqlDataAdapter는 SQL 쿼리 결과를 DataTable에 저장하는 역할을 하며, Fill(DataTable)을 사용하여 데이터를 가져오고, 연결이 자동으로 닫힌다. 그래서 연결을 유지하지 않더라도 DataTable을 활용하여 언제든 사용할 수 있다.

그래서 DataTable이란? SQL에서 가져온 데이터를 메모리 내에서 저장하고 활용할 수 있는 구조이고 Rows, Column 속성을 사용하여 데이터를 조작할 수 있다. 연결이 끊긴 상태에서도 데이터 조작이 가능하다(Disconnection Mode)

dt.Rows란? DataTable에 저장된 모든 행(Row)을 포함하는 컬렉션이며,
개별 행을 가져올 때는 dt.Rows[인덱스] 형태로 사용하고 특정 컬럼 값을 가져오려면 dt.Rows[인덱스][["컬럼명"] 을 사용한다.

foreach를 사용하면 모든 행 데이터를 가져오기가 가능하며 foreach (DataRow row in dt.Rows)를 사용하면 모든 데이터를 반복해서 가져올 수 있다.
이는 여러 개의 데이터를 순회하면서 사용할 때 유용하다.

foreach에 대해서 자세한 점들은 나중에 기회가 된다면 따로 정리를 해보도록 하겠다.


SqlDataReader

마지막으로는 SqlDataReader이다. SqlDataReader는 SQL Server에서 데이터를 가져올 때, 빠르고 효율적으로 읽을 수 있도록 설계된 객체이다.

SqlDataReader의 첫 번째 특징으로는 순방향으로만 데이터를 읽는다. 다시 말해 Forward-only, 앞으로만 읽으므로 한 번 읽은 데이터는 다시 접근이 불가하다.
두 번째 특징으로는 연결된 상태에서 데이터를 읽으며, SqlConnection을 닫을 때까지 데이터를 유지한다.
세 번째 특징으로는 while(reader.Read())로 행을 한 줄씩 처리한다.
마지막으로는 빠른 속도와 적은 메모리 사용이 장점이며, DataTable보다 성능이 좋다! 특히 대량의 데이터를 처리할 때 더욱 강점을 보인다.

이제 SqlDataReader의 사용법을 알아보도록 하자.

우선 이전의 예제처럼 SqlConnetion은 이미 연결되어 열려있다는 상태를 가정하고 진행하도록 하겠다. 그리고 쿼리를 SqlCommand로 불러왔었다.

SqlDataReader dr = cmd.ExcuteReader(); //SQL 실행 후 Reader 반환

while(reader.Read())
{
	int id = reader.GetInt32(0);
    string name = reader.GetString(0);
}

reader.Close();

위의 과정을 설명하자면 SqlDataReader 클래스를 이용한 객체를 만들고 SqlCommand로 불러온 값 들을 dr(DataReader)에 반환해준다.
그리고 앞서 설명한 세 번째 특징처럼 while문 반복을 이용하며 reader.Read() 로 한 행씩 읽게되고, 각 행의 id, name을 각각 GetInt32(), GetString()으로 타입에 맞게 컬럼 값을 가져오는 것이고, reader.Close()를 이용해 데이터 리더를 닫게 된다.

위의 예제처럼 컬럼 인덱스로 값을 가져오는 경우도 있지만 다른 방법도 있으니 소개해보겠다. 하지만 인덱스로 값을 가져오는 것이 가장 빠르다고 하니 기억해두자.

인덱스로 값 가져오는 방법 이외에는 컬럼명을 사용하여 값을 가져오기, Null값 처리(DBNull 체크)도 가능하다.

=============================================================================================================================

//컬럼명을 사용하여 값 가져오기
int id = Convert.ToInt32(reader["ID"]); //ID라는 컬럼명을 사용
string name = reader["Name"].ToString(); //ID라는 컬럼명을 사용

==============================================================================================================================

//Null값 처리 (DBNull 체크)
int? age = reader.IsDBNull(2) ? (Int?)null : reader.GetInt32(2); //IsDBNull(컬럼 인덱스)를 사용해 Null 값을 체크하는 것이 가능하다.

==============================================================================================================================

자바만 배우다 C#을 처음하는 사람은 Null값 처리하는 부분에서 ?에 대해서 잘 모르고 궁금할 것이다.

그래서 잠깐 빠르게 설명하고 지나가도록 하겠다.

자바에서는 기본적으로 int?와 같은 Nullable 타입이 없다. 또한 int, double, boolean, char와 같이 기본형 타입(Primitive Type)은 null을 저장할 수 없고 클래스(Class), 배열(Array), 인터페이스(Interface), 열거형(Enum), Wrapper 클래스(Integer, Double, Boolean, Character) 등과 같은 참조형 타입(Reference Type)의 경우만 null을 가질 수 있다.

하지만 C#에서는 Java에서 기본형 타입과 비슷한 값 타입에서 Nullable 타입을 선언하여 null을 저장할 수 있다.

위의 설명과 같이 C#에서는 값 타입에서 Nullable타입을 선언하여 null을 저장하고 사용할 수 있게 되어있으므로, int?null 값을 가질 수 있는 int형 변수라는 뜻이 된다.

뒤에 있는 물음표는 자바에서도 있는 삼항 연산자이며 조건 ? 참일 때 값 : 거짓일 때 값이며 조건이 참이면 앞의 값, 거짓이면 뒤의 값이 실행된다.

다시 예제로 돌아와서 int? age = reader.IsDBNull(2) ? (int?)null : reader.GetInt32(2);라는 것은null값을 저장할 수 있는 Nullable<int> 타입의 age 변수가 있으며,
해당 변수에는 reader.IsDBNull(2)로 컬럼 인덱스 2번의 컬럼이 NULL이면 null을 저장하고, NULL이 아닐 경우 reader.GetInt32(2)를 통해 int 값을 가져와 저장한다.

마무리

지금까지 C#에서 SQL Server와 연동하여 데이터를 다루는 방법에 대해 정리해보았다.
특히, SqlConnection, SqlCommand, SqlDataAdapter, SqlDataReader 등의 핵심 클래스를 통해 데이터베이스와 어떻게 상호작용하는지에 대해 학습했다.

자바와 비교했을 때 C#의 Nullable<T> 타입과 SQL의 NULL 값을 처리하는 방식이 다소 생소할 수 있고, 아직은 많이 부족하겠지만 이를 이해하면 보다 안전하고 유연한 데이터 처리 로직을 구현할 수 있을 것 같다.

이제 막 C#과 .NET 개발을 시작했지만, 한 걸음씩 나아가면서 꾸준히 학습해야겠다.
이 글이 이후에 다시 학습할 때 좋은 참고 자료가 될 수 있기를 바라며, 앞으로도 지속적인 정리를 통해 성장해 나가야겠다.

profile
백엔드 개발자

0개의 댓글