일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 반복문
- 예약어
- SQL튜닝
- 자바의정석
- SQL
- 상속
- 이클립스 설치
- 친절한 SQL 튜닝
- 객체
- 오버라이딩
- 오버로딩
- 배열
- StringBuffer
- 연산자
- 비교 연산자
- 스프링시큐리티 로그아웃
- 식별자
- java
- SpringSecurity 로그아웃
- spring 게시판 삭제
- SQL 튜닝
- 함수
- join
- 인텔리제이 Web 애플리케이션
- @PreAuthorize("isAuthenticated()")
- SpringSecurity 로그인
- 객체지향
- 산술 연산자
- 친절한 SQL
- 논리 연산자
- Today
- Total
gi_dor
사이드 프로젝트 메모장 본문
해당 폼이 로드될 때 데이터베이스 연결을 시도하고 연결에 성공, 실패 여부 메세지를 보여준다
또한 버튼 클릭시 데이터를 조회하는 코드이다
namespace Helper
{
public partial class CommonCod : Form
{
// 데이터베이스 연결
public static String uid = "";
public static String password = ""; // 비밀번호가 없으므로 빈 문자열
public static String database = "";
public static String server = "";
public static String conStr = $"Server={server}; Database={database}; User Id={uid}; Password={password}; Integrated Security=True";
SqlConnection conn = new SqlConnection(conStr);
private void CommonCod_Load(object sender, EventArgs e)
{
try
{
conn.Open();
MessageBox.Show("Success , DB 연결 되었습니다 ", "DB 연결메세지", MessageBoxButtons.OK, MessageBoxIcon.Information);
// 해당 컬럼의 ReadOnly 속성 true
cod_dataGridView1.ReadOnly = true;
cod_dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
} catch(Exception ex){
MessageBox.Show($"DB 연결실패 \r\n Error : {ex.Message}", "DB Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void CodeManageButton_Click(object sender, EventArgs e)
{
try
{
String sqlQuery = " SELECT * FROM dbo.COD order by COD_NO ASC";
// SQL 쿼리를 실행하기 위한 객체
SqlCommand cmd = new SqlCommand(sqlQuery, conn);
// SqlDataAdapter 는 DB에서 데이터를 가져와 Data Table을 채운다
SqlDataAdapter dataAdapter = new SqlDataAdapter(cmd);
// 가져온 데이터를 담기
DataTable dataTable = new DataTable();
// 데이터 어댑터를 통해 데이터를 데이터 테이블에 채움
dataAdapter.Fill(dataTable);
// 데이터 테이블을 DataGridView에 연결
cod_dataGridView1.DataSource = dataTable;
}
catch (Exception ex)
{
MessageBox.Show($"데이터 조회 실패 \r\n Error : {ex.Message}", "DB Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
데이터베이스에 연결이 열리면 , 연결을 끊는 로직이 필요 할수가 있다
연결을 끊지 않으면 리소스가 소모되므로 , 폼이 닫힐 때 연결을 해제하는것이 좋다
이것을위해 2가지 방법이 있다고 한다 using 과 Dispose()
SqlConnection과 SqlCommand는 둘 다 Dispose()를 구현한 객체지만 사용자가 Dispose()를 호출하지 않았기 때문에 finalizer가 호출될 때까지 메모리에 남게 된다.
using { } 구문은 코드의 블럭이 끝나면 자동으로 Dispose()를 호출한다 , 이것을 통해 Dispose() 를 호출하지 않아도
안전하게 리소스를 해제할수 있다
using{ } 구문을 사용해 코드 수가 감소함
namespace Helper
{
public partial class CommonCod : Form
{
// 데이터베이스 연결
public static String uid = "";
public static String password = ""; // 비밀번호가 없으므로 빈 문자열
public static String database = "";
public static String server = "";
public static String conStr = $"Server={server}; Database={database}; User Id={uid}; Password={password}; Integrated Security=True";
public CommonCod()
{
InitializeComponent();
}
private void CommonCod_Load(object sender, EventArgs e)
{
try
{
using (SqlConnection conn = new SqlConnection(conStr))
{
conn.Open();
MessageBox.Show("Success, DB 연결 되었습니다", "DB 연결 메시지", MessageBoxButtons.OK, MessageBoxIcon.Information);
// 해당 컬럼의 ReadOnly 속성 true
cod_dataGridView1.ReadOnly = true;
cod_dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
}
}
catch (Exception ex)
{
MessageBox.Show($"DB 연결 실패 \r\n Error: {ex.Message}", "DB Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void CodeManageButton_Click(object sender, EventArgs e)
{
try
{
String sqlQuery = "SELECT * FROM dbo.COD ORDER BY COD_NO ASC";
// using 구문을 사용하여 SqlConnection을 자동으로 닫음
using (SqlConnection conn = new SqlConnection(conStr))
{
SqlCommand cmd = new SqlCommand(sqlQuery, conn);
SqlDataAdapter dataAdapter = new SqlDataAdapter(cmd);
DataTable dataTable = new DataTable();
dataAdapter.Fill(dataTable);
// 데이터 테이블을 DataGridView에 연결
cod_dataGridView1.DataSource = dataTable;
}
}
catch (Exception ex)
{
MessageBox.Show($"데이터 조회 실패 \r\n Error: {ex.Message}", "DB Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
명시적인 Disposs()
namespace Helper
{
public partial class CommonCod : Form
{
// 데이터베이스 연결
public static String uid = ";
public static String password = ""; // 비밀번호가 없으므로 빈 문자열
public static String database = "";
public static String server = "";
public static String conStr = $"Server={server}; Database={database}; User Id={uid}; Password={password}; Integrated Security=True";
public CommonCod()
{
InitializeComponent();
}
private void CommonCod_Load(object sender, EventArgs e)
{
try{
MessageBox.Show("불러오기 성공", "정보", MessageBoxButtons.OK, MessageBoxIcon.Information);
// 해당 컬럼의 ReadOnly 속성 true
cod_dataGridView1.ReadOnly = true;
cod_dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
}
catch (Exception ex)
{
MessageBox.Show($"DB 연결 실패 \r\n Error: {ex.Message}", "DB Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void CodeManageButton_Click(object sender, EventArgs e)
{
SqlConnection conn = null;
try
{
String sqlQuery = "SELECT * FROM dbo.COD ORDER BY COD_NO ASC";
conn = new SqlConnection(conStr);
SqlCommand cmd = new SqlCommand(sqlQuery, conn);
SqlDataAdapter dataAdapter = new SqlDataAdapter(cmd);
DataTable dataTable = new DataTable();
dataAdapter.Fill(dataTable);
// 데이터 테이블을 DataGridView에 연결
cod_dataGridView1.DataSource = dataTable;
}
catch (Exception ex)
{
MessageBox.Show($"데이터 조회 실패 \r\n Error: {ex.Message}", "DB Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
// 연결을 닫고 자원을 해제
if (conn != null)
{
conn.Dispose(); // 명시적으로 Dispose() 호출
}
}
}
}
}
using (SqlConnection conn = new SqlConnection(conStr))
{
conn.Open();
// 데이터베이스 작업 수행
} // using 블록을 벗어나면 자동으로 Dispose()가 호출됨
Dispose() 수동으로 리소스를 해제 하기 위해 코드를 명시적으로 작성해 호출한다
SqlConnection conn = new SqlConnection(conStr);
try
{
conn.Open();
// 데이터베이스 작업 수행
}
finally
{
// 리소스를 수동으로 해제
if (conn != null)
{
conn.Dispose(); // 명시적으로 Dispose() 호출
}
}
** C# GC에 대해
C#은 가비지 컬렉터가 메모리를 자동으로 관리한다
대신 필요없는 클래스의 인스턴스를 메모리에서 바로 지우는게 아니라 조건이 될 때까지 기다렸다가 지우기 때문에 클래스를 지웠다고 해도 그게 실제로 바로 삭제되는 것은 아니다.
Dispose를 호출하는 걸 깜박하면 어떻게 될까?
그럴 경우에는 GC에서 해당 인스턴스를 제거할 때, (소멸자에서) Dispose를 호출해준다.
다만 다음과 같은 부작용이 생길 수 있다고 한다.
1.GC가 해당 인스턴스를 언제 지울 지 알 수 없다.
Dispose가 언제 호출될지 알 수 없다. 애플리케이션이 종료될 때까지 호출이 안될 수도 있다. 중요한 리소스를 사용하거나, 메모리를 많이 먹는 클래스라면 위험할 수도 있겠다.
2.GC가 해당 인스터스를 지울 때 Dispose를 호출하게 되면 그 순간 부하가 걸린다.
즉, 랜덤하게 랙을 유발할 수도 있다. 성능에 예민한 앱이라면 주의가 필요하다.
3.GC가 해당 인스턴스를 지울 때 Dispose에서 예외가 발생하면 어플 자체가 크래시 할 수도 있다.
수동으로 Dispose를 할 때에는 try/catch로 보호할 수 있지만, 자동제거일 경우 예외를 잡을 수 없기 때문에 매우 위험할 수도 있다
자바의 가비지 컬렉션은 프로그래머가 GC를 호출할수 없으며 , JVM이 메모리 상황을 모니터링하다가 필요시 GC를 자동으로 실행한다
C# 에서 가비지 컬렌셕도 메모리가 부족하거나 특정조건이 될 때 GC가 실행되며 직접적인 컨트롤없이 처리를한다
다만 GC.Collect()를 메서드를 호출하면 프로그래머가 GC를 유발할수 있지만 시스템에 부하를 준다고 한다
자바는 기본적으로 시스템이 메모리를 관리하고 하며 , 개발자는 신경쓰지 않게 설계 되어있다
C#은 개발자에게 약간의 메모리 관리 권한을 부여하며 Dispose() 와 using { } 구문을 통해 리소스를 해체하는 패턴을 사용
자원을 다룰 때 using 키워들 이용하자
- using 키워드를 이용하면 괄호( {} )를 빠져나올 때 자동으로 Dispose를 해준다.
여기서 자원이란 파일, 폰트 등과 같은 Resource를 말한다.
데이터베이스 연결 및 리소스 관리
프로젝트에서 데이터베이스와의 연결을 효과적으로 관리하기 위해, using 구문을 사용하여 SqlConnection 객체를 처리하였습니다. using 구문을 사용하면 데이터베이스 연결과 같은 리소스가 자동으로 해제되므로, 연결을 수동으로 닫는 것을 잊을 염려가 없으며, 리소스 누수 문제를 예방할 수 있습니다. 이를 통해 코드의 안정성과 유지보수성을 향상시킬 수 있었습니다.
코드 예시:
private void CodeManageButton_Click(object sender, EventArgs e)
{
try
{
String sqlQuery = "SELECT * FROM dbo.COD ORDER BY COD_NO ASC";
using (SqlConnection conn = new SqlConnection(conStr))
{
conn.Open();
SqlCommand cmd = new SqlCommand(sqlQuery, conn);
SqlDataAdapter dataAdapter = new SqlDataAdapter(cmd);
DataTable dataTable = new DataTable();
dataAdapter.Fill(dataTable);
cod_dataGridView1.DataSource = dataTable;
}
}
catch (Exception ex)
{
MessageBox.Show($"데이터 조회 실패 \r\n Error : {ex.Message}", "DB Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
주요 사항:
- 자동 리소스 관리: using 구문을 활용하여 SqlConnection 객체를 생성하고 사용 후 자동으로 리소스를 해제합니다. 이는 메모리 누수 및 리소스 낭비를 방지합니다.
- 에러 처리: 데이터베이스와의 상호작용 중 발생할 수 있는 예외를 적절히 처리하여 사용자에게 친절한 에러 메시지를 제공하고, 프로그램의 안정성을 높였습니다.
- 폼 종료 시 연결 해제: 폼이 닫힐 때 데이터베이스 연결을 안전하게 종료하도록 using 구문을 사용하면 SqlConnection 객체는 블록이 끝나면 자동으로 닫히기 때문에, FormClosing 이벤트에서 별도로 연결을 해제하는 코드를 작성할 필요가 없습니다 블록을 벗어나면 자동으로 Dispose() 메서드가 호출되어 리소스가 정리
따라서 CodeManageButton_Click 메서드와 같은 경우에는 SqlConnection을 using 구문으로 처리하여 리소스 관리를 자동으로 할 수 있으며, 폼이 닫힐 때 별도로 연결을 해제할 필요는 없습니다.
dateGridView에서 해당컬럼 선택시 해당하는 컬럼의 값만 복사가 되었는데
엑셀 작업으로 데이터를 전송하는 경우가 자주 발생해 해당 컬럼 선택시 해당하는 행의 모든 컬럼의 값을 가져오기 위해
SelectionMode의 값을 FullColumnSelect를 선택된 행의 전부선택되게 설정했습니다.
에러
dataGridView에서 DB에 맞게 해당 테이블의 컬럼을 설정하여 만들었다
컬럼이 중복이 되어 조회되는것을 확인했다
해결책이 몇가지 있어 시도를했다
1. winform 에서 dataGridView에 설정한 컬럼을 삭제한뒤에 사용
→ 사용자 입장으로서 최악의 선택이다 버튼을 클릭시 해당 컬럼과 값은 제대로 들어가지만 조회 버튼 누르기 전까지는 하얀 빈공간으로 보여진다
2. dataGridView에 컬럼을 작성 후에 조회 클릭이벤트를 발생하는 메서드에
cod_dataGridView1.Columns.Clear(); 를 사용해 기존에있던 컬럼들을 모두 삭제하고
데이터를 삽입한다
이렇게하면 초기화면에서 사용자는 컬럼명들을 볼수 있고
조회 이벤트 발생시 중복된 컬럼없이 알맞은 데이터들을 볼수 있다
또한 코드로 컬럼을 생성하지 않고 winform에서 속성창을 이용해서 컬럼을 만들기에 더 쉽고 간편하고 코드의 양이 줄어든다
dataGrideView1 에서 송장을 클릭하게되면 해당 송장번호에 맞는 상세 정보들을 볼수 있다
하단에 비어있는 행을 클릭후 삭제 요청시
String INV_NO = ScanDataGridView2.SelectedRows[0].Cells["INV_NO"].Value.ToString();
System.Windows.Forms.DataGridViewCell.Value.get이(가) null을(를) 반환했습니다.
System.NullReferenceException은 Value 속성이 null인 경우 발생한다
ToString() 메서드를 호출하기 전에 Value가 null인지 확인하는 것이 필요하다
지금까지 사용했던 String.IsNullOrWhiteSpace는 null 값뿐만 아니라 빈 문자열이나 공백 문자열도 처리할 수 있지만, Value 속성이 null인 경우에는 ToString()을 호출하기 전에 확인이 필요하다
해당 예외를 처리하기 위해 2가지 방법이있다
1. Value?.ToString()
2. ScanDataGridView2에 AllowUserToAddRTows 속성을 FALSE 로 설정한다
Value?.ToString() 를 사용하게되면 Value의 값이 null이라면 ToString() 메서드가 호출되지 않아서
INV_NO는 null 이되며 NULL 참조 오류를 방지할 수 있다
AllowUserToAddRTows 속성은 행의 추가 옵션이 사용자에게 표시되는지 여부를 보여주는 속성이다
ScanDataGridView2에 AllowUserToAddRTows 속성의 기본값은 TRUE 이지만 FALSE 로 설정하게되면
해당 사진처럼 하단에 비어있는 행이 추가 되지 않아 선택조차 할수 없게 설정할 수 있다.
만약 INSERT 를 하는 기능을 구현한다면 Value?.ToString() 을 사용해야 하지만
해당 프로그램은 ScanData에 대해 데이터 추가기능은 제한 하기에 늘어나는 코드양도 없으며 손쉽게 구현할수 있기에
AllowUserToAddRTows 속성을 선택했다
String sqlQuery = "SELECT top 100000 " +
" A.INV_NO as '송장번호' ," +
" A.BRA_ID as '영업소' , " +
" A.SCANN_SLT as '스캔 상태' , " +
" B.COD_CONT as '코드 내용' , " +
" A.SCANN_DATE as '스캔 일자' , " +
" A.SCANN_TIME as '스캔 시간' , " +
" A.CAR_ID as '배송 차량' , " +
" A.SCANN_USR_ID as '스캔 ID' , " +
" A.TRS_ID as '처리자 ID' , " +
" A.TRS_NAME as '처리자 명' , " +
" A.TRS_DATE as '처리 일자'" +
" FROM SLIS_MASTER.dbo.LS101T0 A " +
" INNER JOIN SLIS_MASTER.dbo.LS901T0 B " +
" ON A.SCANN_SLT = B.COD "+
" ORDER BY A.SCANN_DATE DESC , A.SCANN_TIME DESC";
'Language > C#' 카테고리의 다른 글
C# string 초기화 (0) | 2024.08.06 |
---|