1. Connection
이제부터는 좀더 구체적으로 알아보도록 하겠다
어떤 작업을 하던 간에 일단 데이터베이스와 연결을 해야 한다. ADO.NET 에서 연결을 담당하는 객체가 바로 Connection 객체인데 그 사용방법은 아래와 같다.
간단하지 않은가? 하지만 이 상태로라면 데이터베이스에 연결할 정보를 아무것도 주지 않은 상태이다.
위와 같이 ConnectionString 속성에 연결 문자열을 설정해 주어야 제대로 연결이 된다.
이 과정을 한번에 할 수도 있다.
예전에 ADO를 사용해서 개발해 본 개발자들이라면 뭔가 연결 문자열이 간단하다는 생각을 하게 될 것이다. 바로 “Provider = SQLOLEDB” 이 부분이 없어졌기 때문이다. SqlConnection은 이미 SQL Server에 연결 한다는 사실을 알기 때문에 더 이상 공급자를 지정하거나 할 필요가 없다. 하지만 여러분들이 OLE DB Data Provider를 사용해야 한다면 반드시 지정을 해야 할 것이다.
2. Connection Events
Connection 객체는 아래와 같이 세 가지 이벤트를 사용할 수 있다.
- Disposed
- StateChange
- InfoMessage
이중에서 Disposed Event는 System.Component에서 상속 받은 것으로 개체가 소멸될 때 발생한다. 아마도 거의 모든 객체서 볼 수 있을 것이다.
StateChange Event
StateChange Event는 Connection 객체의 상태가 바뀔 때 발생한다. 간단한 예를 보면 쉽게 이해 할 수 있을 것이다.
{
const string CONNECTION_STRING = "Persist Security Info=False;Integrated Security=SSPI;database=northwind;server=mySQLServer";
const string SELECT_ALL = "select * from Products";
SqlDataAdapter rAdapter = new SqlDataAdapter(SELECT_ALL, CONNECTION_STRING);
// add handlers
rAdapter.SelectCommand.Connection.StateChange += new StateChangeEventHandler(OnStateChange);
// create dataset
DataSet rDataSet = new DataSet();
// fill dataset,
// DataAdapter will open connection, load data and restore connection state - close connection.
// as result it fires several StateChange events
rAdapter.Fill(rDataSet, 0, 5, "Table");
}
{
Console.WriteLine("OnStateChange");
Console.WriteLine(" event args: ("+ "originalState=" + args.OriginalState + " currentState=" + args.CurrentState +")");
}
여기서 반드시 숙지할 것은 Event를 사용하기 위해서는
와 같이 객체의 Event와 EventHandler를 연결시켜야 한다는 점이다.
InfoMessage
InfoMessage Event는 Provider가 Client에 경고나 메시지를 보내고자 할 때마다 시작된다.
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
{
public static SqlConnection con;
public static void Main()
{
con = new SqlConnection(ConfigurationSettings.AppSettings["constring"] );
con.InfoMessage += new SqlInfoMessageEventHandler(InfoMessage);
SqlCommand cmd = new SqlCommand("PRINT 'This is a test'", con);
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
while(reader.Read())
{
Console.WriteLine("{0} - {1}", reader.GetString(0), reader.GetString(1));
}
con.Close();
Console.ReadLine();
{
for(int i=0; i < e.Errors.Count; i++)
{
Console.WriteLine("{0} - {1}", "InfoMessage", e.Errors[0].ToString());
}
}
}
}
위의 소스에서 강제로 InfoMessage Event를 발생시키기 위해서 PRINT 문을 사용했다. InfoMessage Event를 사용하기 위해서도 받드시 아래와 같이 이벤트 핸들러를 등록해 주어야 한다.
3.Data Provider에서의 연결 풀링(Connection Pooling)
.NET Data Provider들은 직접 연결 Pooling을 자동적으로 관리하므로 개발자들이 직접 연결을 관리할 필요가 없다.
연결 풀링을 공유하는 방법은 데이터베이스 연결문자를 계속 반복해서 사용하면 된다. 또 연결 풀링을 새로 시작하는 방법 역시 데이터베이스 연결문자를 다르게 사용하면 새로운 풀링을 사용할 수 있게 된다.
풀링에 관한 내용은 모두 SqlConnection 객체가 관리하며 풀링에 대한 설정은 SqlConnection 객체의 ConnectionString에 의해서 설정할 수 있다.
이름 | 기본값 | 설명 |
Connection Lifetime | 0 | 연결이 풀로 반환되면 만든 시간을 현재 시간과 비교하여 그 간격(초)이 Connection Lifetime에서 지정한 값을 초과하면 연결이 소멸됩니다. 이것은 클러스터링된 구성에서 실행 중인 서버와 방금 온라인 상태가 된 서버 사이의 로드 균형을 강제로 조정하는 데 유용합니다. 값 0은 풀링된 연결이 최대 시간 제한을 갖도록 합니다. |
Connection Reset | 'true' | 풀에서 제거될 때 데이터베이스 연결이 다시 설정되는지 여부를 결정합니다. Microsoft SQL Server 버전 7.0의 경우 false로 설정하면 연결을 가져올 때 추가적인 서버 라운드트립이 발생하지 않지만 데이터베이스 컨텍스트와 같은 연결 상태는 다시 설정되지 않습니다. |
Enlist | 'true' | true이면 풀러는 트랜잭션 컨텍스트가 있는 경우 해당 연결을 만들기 스레드의 현재 트랜잭션 컨텍스트에 자동으로 참여시킵니다. |
Max Pool Size | 100 | 풀에서 허용되는 최대 연결 수입니다. |
Min Pool Size | 0 | 풀에서 유지되는 최소 연결 수입니다. |
Pooling | 'true' | true이면 연결이 적절한 풀에서 선택되거나, 필요한 경우 연결이 만들어져 적절한 풀에 추가됩니다. |
4.Command 사용하기
SqlCommand객체는 명령을 사용하기 위해서 몇 가지 중요한 속성들을 가지고 있다.
- CommandText: SQL이나 저장 프로시저를 등록할 수 있다.
- CommandType:
CommandType은 실행시킬 명령의 종류를 설정할 수 있다.
Text: 일반 SQL Query
TableDirect: 반환되는 테이블 이름
StoredProcedure: 저장 프로시저
- Connection:
데이터베이스 연결에 사용할 연결 객체를 지정할 수 있다.
SqlCommand 객체의 생성자는 아래와 같이 4가지 형태로 사용할 수 있다.
public SqlCommand();
public SqlCommand(string);
public SqlCommand(string, SqlConnection);
public SqlCommand(string, SqlConnection, SqlTransaction);
5.Command 실행하기
Command 객체를 실행하는데 있어서 아래와 같이 4가지 명령을 사용할 수 있다.
ExecuteNonQuery
ExecuteReader
ExecuteScalar
ExecuteXmlReader
각각의 사용방법은 나름데로 다들 잘 알 테니 아래 샘플들로 설명을 대신하도록 하겠다.
ExecuteNonQuery
{
SqlCommand myCommand = new SqlCommand(myExecuteQuery, myConnection);
myCommand.Connection.Open();
myCommand.ExecuteNonQuery();
myConnection.Close();
}
ExecuteReader
{
SqlConnection myConnection = new SqlConnection(myConnectionString);
SqlCommand myCommand = new SqlCommand(mySelectQuery, myConnection);
myConnection.Open();
SqlDataReader myReader = myCommand.ExecuteReader(CommandBehavior.CloseConnection);
while(myReader.Read())
{
Console.WriteLine(myReader.GetString(0));
}
myReader.Close();
//Implicitly closes the connection because CommandBehavior.CloseConnection was specified.
}
ExecuteScalar
Int32 count = (int32) cmd.ExecuteScalar();
ExecuteXmlReader public void CreateMyXmlReader(string myXmlQuery, SqlConnection myConnection)
{
SqlCommand myCommand = new SqlCommand(myXmlQuery, myConnection);
try
{
myConnection.Open();
System.Xml.XmlReader myXmlReader = myCommand.ExecuteXmlReader();
// Always close the XmlReader when finished.
myXmlReader.Close();
}
catch(Exception e)
{
System.Diagnostics.EventLog log = new System.Diagnostics.EventLog();
log.Source = "My Application";
log.WriteEntry(e.ToString());
Console.WriteLine("Exception of type {0} occurred.", e.GetType());
}
finally
{
myConnection.Close();
}
}
Command 객체를 통해서 저장프로시저를 실행하고자 할 때는 CommandType에서 StoredProcedure를 지정하기만 하면 해당 명령이 저장프로시저로 간주하게 된다.
SqlCommand salesCMD = new SqlCommand("SalesByCategory", nwindConn);
salesCMD.CommandType = CommandType.StoredProcedure;
6.매개변수화된 T-SQL과 Query 사용하기
매개변수화된 T-SQL이라 제목은 거창하지만 사실은 이제까지 내용과 크게 다를 바 없는 내용이다. 단 한가지 달라지는 점이 있다면 Parameters 객체를 사용한다는 차이점이 있다.
Parameters 객체를 사용해 본적이 있는 사람도 있을 것이다. ADO에서도 존재 했었고 사용하는 방법 또한 ADO에서와 크게 다르지 않은 방법으로 사용할 수 있다.
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
public class USACustomers
{
public static void Main()
{
SqlConnection con = new SqlConnection( ConfigurationSettings.AppSettings["constring"] );
SqlCommand cmd = new SqlCommand("SELECT * FROM Customers WHERE Country = @country; " + "SELECT @count = COUNT(*) FROM Customers WHERE Country = @country", con);
cmd.Parameters.Add(new SqlParameter("@country", SqlDbType.VarChar, 50)).Value = "USA";
cmd.Parameters.Add(new SqlParameter("@count", SqlDbType.Int));
cmd.Parameters["@count"].Direction = ParameterDirection.Output;
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
while(reader.Read())
{
Console.WriteLine("{0} - {1}", reader.GetString(0), reader.GetString(1));
}
reader.Close();
Console.WriteLine("{0} - {1}","Count",cmd.Parameters["@count"].Value.ToString());
con.Close();
Console.ReadLine();
}
}
설명도 하지 않고 소스만 쭈욱 늘어뜨린 나를 원망하는 사람도 있을 것이다. 하지만 정작 알게 되면 별반 어려운 내용은 결코 아니니 긴장 하지 않으셔도 된다.
위의 내용은 몇 가지 Parameter를 사용하는 Query의 예를 보여주고 있다.
이렇게 Parameter를 사용하는 예를 보여주면
SELECT * FROM Customers WHERE Country = @country 이부분을
“SELECT * FROM Customers WHERE Country =” + “USA” 요렇게 사용하고 싶은 사람들이 많을 것이다.
하지만 위의 두 Query에는 분명한 차이점이 존재한다.
여러 번 실행될 때 Pararmeters 객체를 사용하면 모두 같은 Query로 인식되고 값만 다른 동일한 Query로 인식되기 때문에 SQL Server에서 수행하는 여러 단계의 Query분석 단계가 사실상 생략된다. 하지만 Paramters객체를 사용하지 않는 경우는 매번 다른 Query로 인식되어 항상 분석과 검증 그리고 계획 단계를 거치기 때문에 속도가 떨어질 수 밖에 없다.
저장 프로시저를 Parameters 객체를 이용해서 사용하는 방법도 크게 다르지 않다.
정리
이렇게 전반적인 .NET Data Provider와 중요한 몇 가지 사항을 살펴보았다. 다음장에서는 Visual Studio안에서 ADO.NET을 어떻게 멋지게 지원하는가를 보도록 하겠다.
- ADO for Performance (0)2007/01/09
- ADO 데이타 바인딩 다이얼로그 얻기 (0)2007/01/09
- ADO.NET is not built in a day (0)2006/08/12
- .NET Data Provider(2) (0)2006/08/12
- .NET Data Provider(1) (0)2006/08/12

수안이의 컴퓨터 연구실



Leave your greetings.