원래 Oracle의 XML관련 패키지를 설치하면 쿼리 결과를 바로 XML로 받을수 있지만
DBA에 요청하니 시스템 관리 업체에 얘기해서 뭐 어쩌고 저쩌고..
어제오전에 얘기했는데.. 하루가 지난 오늘도 설치가 안돼 있다.
그래서.. 테스트도 할 겸 C#으로 간단하게 만들었다.
처리의 핵심은 복잡한 쿼리 결과를 웹으로 조회할 경우
접속과 요청이 있을때마다 쿼리를 보내게 되므로 커넥션쪽에도 부하가 걸리고
DB쿼리에도 부하가 걸려 전체적인 DB성능에 영향을 주게 되므로
지정간격으로 DB를 쿼리하고(물론 요청이 없으면 하지 않음) XML을 만들어
그 XML을 웹페이지가 가져가서 처리하도록 하는것이다.
지속적으로 파일을 만드는 일이라 물리DISK의 특정위치에 대한 집중적 사용으로
손상도 우려되어 5개의 파일 정도를 계속 유지할 수 있도록 하였고
XML기록중 다른 프로세스가 읽는것을 방지하기 위하여
쿼리와 동시에 XML을 바로 기록하지 않고 단번에 기록할수 있게 결과 완료후 기록하도록 했다.
쿼리문의 결과를 XML형태로 만들어 반환 (String)
메모리스트림을 사용하므로 물리적 디스크 Access가 없음
// 쿼리결과를 XML로 만들어 반환
private string makeQueryToXML(string connStr, string sql)
{
string result = "";
OracleConnection DB = null;
MemoryStream ms = null;
try
{
DB = new OracleConnection(ConfigurationManager.ConnectionStrings[connStr].ConnectionString);
DB.Open();
OracleDataAdapter adapter = new OracleDataAdapter();
adapter.SelectCommand = new OracleCommand(sql, DB);
DataSet ds = new DataSet();
adapter.Fill(ds);
// 자료가 있어야만 XML 생성
if (ds.Tables[0].Rows.Count > 0)
{
string[] colName = new string[ds.Tables[0].Columns.Count];
for (int i = 0; i < ds.Tables[0].Columns.Count; i++)
colName[i] = ds.Tables[0].Columns[i].ColumnName.Trim();
ms = new MemoryStream();
// XML 생성
XmlTextWriter textWriter = new XmlTextWriter(ms, Encoding.UTF8);
// 들여쓰기 설정
textWriter.Formatting = Formatting.Indented;
// 문서에 쓰기 시작
textWriter.WriteStartDocument();
// 루트 설정
textWriter.WriteStartElement("ROWSET");
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
// ROW 노드와 값 설정
textWriter.WriteStartElement("ROW");
textWriter.WriteStartAttribute("num");
textWriter.WriteValue(i + 1);
textWriter.WriteEndAttribute();
// COLUMN 노드 값 설정
for (int j = 0; j < ds.Tables[0].Columns.Count; j++)
{
textWriter.WriteStartElement(colName[j]);
textWriter.WriteString(ds.Tables[0].Rows[i][j].ToString());
textWriter.WriteEndElement();
}
textWriter.WriteEndElement();
}
textWriter.WriteEndElement();
textWriter.WriteEndDocument();
textWriter.Close();
result = Encoding.UTF8.GetString(ms.GetBuffer()).Trim();
ms.Close();
ms.Dispose();
ms = null;
}
DB.Close();
return result;
}
catch (Exception ex)
{
Response.Write(ex.ToString());
return result;
}
finally
{
if (ms != null)
{
ms.Close();
ms.Dispose();
}
if (DB != null)
DB.Close();
}
}
1. 지정시간 이내에 만들어진 XML이 있는지 검사.
2. 있을경우 크기가 10바이트 미만이면 다른 프로세서가 XML을 생성중인 것으로 판단 직전생성된 XML 파일이름을 Return (끝)
3. 10바이트 보다 크면 정상적인 XML파일로 판단 파일이름 Return (끝)
3. 없을경우 오래된 XML파일을 삭제(항상 동일 갯수만 생성되어 있도록 유지)
4. 0바이트의 XML파일을 만듦 : XML자료 생성 도중 다른 프로세스가 읽어가는것을 방지
5. makeQueryToXML로 부터 받아온 XML데이터를 파일로 저장함
6. 새로 만들어진 XML 파일이름을 Return (끝)
private string makeXML(string path, string prefix, string connStr, string sql, int delay_second)
{
// 반복간격이 5초 미만이면 처리하지 않음
if (delay_second < 5)
return "";
string result = "";
FileStream fs = null;
StreamWriter writer = null;
OracleConnection DB = null;
try
{
DirectoryInfo di = new DirectoryInfo(path);
FileInfo[] fi = di.GetFiles(prefix + "*.xml");
if (fi.Length > 0)
{
// 마지막 자료와의 시간차 구하기
int lastCnt = fi.Length - 1;
string check = fi[lastCnt].Name.Replace(".xml", "").Replace(prefix, "");
DateTime cdate = DateTime.Parse(check.Substring(0, 4) + "-" + check.Substring(4, 2) + "-" +
check.Substring(6, 2) + " " + check.Substring(8, 2) + ":" + check.Substring(10, 2) + ":" +
check.Substring(12, 2));
TimeSpan ts = DateTime.Now - cdate;
if (ts.Seconds < delay_second)
{
// 파일크기가 10바이트 미만이면 직전 파일명 반환 : 현재 XML 생성중으로 판단
if (fi[lastCnt].Length < 10)
lastCnt--;
return fi[lastCnt].FullName;
}
// 오래된 XML 삭제
try
{
for (int i = 0; i < (fi.Length - 4); i++)
{
File.Delete(fi[i].FullName);
}
}
catch
{
}
}
// XML 파일 생성: 0 Byte
result = path + "\\" + prefix + string.Format("{0:yyyyMMddHHmmss}", DateTime.Now) + ".xml";
fs = new FileStream(result, FileMode.Create);
writer = new StreamWriter(fs);
writer.Close();
fs.Close();
// XML 자료 생성
string xmlResult = makeQueryToXML(connStr, sql);
// XML 파일 기록 : 실제 내용 기록
fs = new FileStream(result, FileMode.Append);
writer = new StreamWriter(fs);
writer.WriteLine(xmlResult);
writer.Close();
fs.Close();
return result;
}
catch (Exception ex)
{
Response.Write(ex.ToString());
// 오류 났으면 삭제해 버림
if (result != "")
{
if (File.Exists(result))
File.Delete(result);
}
return "";
}
finally
{
if (writer != null)
writer.Close();
if (fs != null)
fs.Close();
if (DB != null)
DB.Close();
}
}
XML을 읽어서 ArrayList [string[]] 으로 Return
Client에서 XML자체를 받아 파싱할수도 있지만, 편한대로 처리함
/// <summary>
/// XML을 읽어서 결과 ArrayList를 되돌려준다.
/// </summary>
/// <param name="filename">XML 파일</param>
/// <param name="field_list">필드 목록 : 대소문자 구분해야함!</param>
/// <returns></returns>
private ArrayList ReadXML(string filename, string[] field_list)
{
ArrayList result = new ArrayList();
try
{
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(filename);
XmlElement root = xmldoc.DocumentElement;
// 노드 요소들
XmlNodeList nodes = root.ChildNodes;
// 노드 요소의 값을 읽어 옵니다.
foreach (XmlNode node in nodes)
{
if (node.Name.ToLower().Trim() == "row")
{
string[] row = new string[field_list.Length];
for (int i = 0; i < field_list.Length; i++)
{
row[i] = node[field_list[i]].InnerText;
}
result.Add(row);
}
}
}
catch (Exception ex)
{
Response.Write(ex.ToString());
}
return result;
}
댓글 없음:
댓글 쓰기