새소식

Daily Record

5월 12일 학습 내용 정리

 

 

 

Oracle / JDBC

 

 

1. Oracle

 

 - like 'Pattern' : pattern에 두가지 와일드카드를 사용함( % / _ )

    * % : 길이와 상관 없이(0개 이상) 모든 문자 데이터를 의미

    * _ : 어떤 값이든 상관 없이 한개의 문자 데이터를 의미

-- 성이 이씨인 사원 조회
select ename
from emp
-- where ename = '이'; -- 이름이 "이"인 사원
-- where ename like '이_'; -- 이름이 외자인 사원
where ename like '이%';

-- 이름이 "랑"으로 끝나는 사원
select ename
from emp
where ename like '%랑';

-- 이름에 "성"이 들어가는 사원
select ename
from emp
where ename like '%성%';

-- 이름이 "성"으로 끝나는데, 전체 이름이 3글자인 사원
-- '%성' (x)
select ename
from emp
where ename like '__성';

 

    * not like 'Pattern' : pattern의 반대로 사용

-- 이름에 "성"이 들어가지 않은 사원
select ename
from emp
where ename not like '%성%';

 

 - is null

    * null 여부를 확인하는 연산자

    * null : 현재 무슨 값인지 확정되지 않은 상태(undefined) 또는 값 자체가 존재하지 않는 상태

-- 커미션이 null인 사원
select ename, comm
from emp
-- where comm = null; -- (x)
where comm is null; -- 값이 없기 때문에 =로 비교할 수 없음. is null을 사용해야 함

-- 커미션이 결정된 사원(comm 컬럼 값이 null이 아닌 경우)
select ename, comm
from emp
where comm is not null; -- comm이 0인 사원은 0으로 결정된 것

 

 - order by ColumnName SortKeyword

    * 정렬방식: asc(오름차순-기본값_ascending) / desc(내림차순_descending)

    * 원하는 순서로 출력 데이터 정렬

-- 급여를 적게 받는 사원부터 많이 받는 사원 순으로 정렬
select ename, sal
from emp
order by sal; -- order by sal asc;(오름차순은 정렬방식 생략 가능)

-- 급여 많은 사원부터 적게 받는 순으로 정렬
select ename, sal
from emp
order by sal desc;

-- 사원 이름 순 정렬(문자 데이터는 사전순으로 정렬)
select ename
from emp
order by ename;

-- 입사일 순으로 정렬
select ename, hiredate
from emp
order by hiredate;

-- n차 정렬: 1차 정렬한 데이터 값이 동일할 때 그 이후의 정렬 순서 결정(,로 구분하여 작성)
select ename, sal
from emp
-- order by sal, ename; -- 급여가 같은 경우 이름순 정렬
order by sal asc, ename desc; -- 급여순 정렬, 급여가 같으면 이름의 역순으로 정렬
-- (헷갈릴 수 있으니 asc도 작성해주는 것이 좋음)

 

 - desc : 테이블 구조 확인(describe)

 

 - create table TableName(ColumnName DataType(length)) : 테이블 생성. 여러 개 입력 시 ,로 구분

create table emp01(
    empno number(4), -- 들여쓰기 필수는 아님
    ename varchar2(20), -- 저장공간 가변
    sal number(7, 3) -- 7자리, 소수점 이하 3자리
);

desc emp01; -- emp01 테이블의 구조 확인

 

 - alter table TableName add ColumnName DataType : 테이블에 컬럼 추가(= 테이블 구조 변경)

alter table emp01
add birth date;

 

 - alter table TableName drop column ColumnName : 테이블에서 컬럼 삭제(= 테이블 구조 변경)

alter table emp01
drop column ename; -- 데이터 타입은 작성하지 않음

 

 - alter table TableName modify ColumnName DataType(length) : 테이블의 컬럼 변경(= 테이블 구조 변경)

alter table emp01
modify empno number(5);

alter table emp
modify empno number(3); -- 기존에 존재하는 데이터(4자리)에 따라 테이블 변경이 안될 수도 있음

 

 - rename A to B : 테이블명을 A에서 B로 변경

 

 - drop table TableName : 객체(테이블) 제거

drop table emp02;

desc emp02; -- ERROR : emp02 객체가 존재하지 않습니다.

 

 - insert into TableName(columnName) values(data) : 데이터 삽입(추가)

insert into dept01
    (deptno, dname, loc) -- 생성할 때 입력한 순서와 상관 없음
values
    (10, '경리부', '서울'); -- insert에 작성한 순서와 동일해야 함
    
-- ColumnName을 생략하고 작성 가능(조회했을 때 컬럼 순서대로 value 작성해야 함)
insert into dept01
values (30, '전산부', '부산');

-- 특정 column의 값만 입력할 경우(입력하지 않은 부분은 null)
insert into dept01
    (deptno, dname)
values
    (40, '인사부');
    
-- 값을 null로 입력하여 작성해도 됨
insert into dept01
values (50, '총무부', null);

 

 - update TableName set ColumnName = Value where Conditions : 데이터 수정(갱신)

update dept01
set dname = '생산부'
where deptno = 10; -- deptno가 10인 dname을 생산부로 변경(where 생략 시 dname 전체가 변경됨)

 

 - delete [from] TableName where Conditions : 데이터 삭제

delete dept01
where deptno = 10;

 

 - 테이블 구조만 복사하여 테이블 새로 생성하기

create table dept01
as
select * from dept
where 0 = 1; -- 무조건 거짓 -> 데이터는 가져오지 않음

 

 - 데이터 처리는 모두 행 단위로 실행. 1행 3열의 값을 바꾸고 싶음 -> 데이터 삭제가 아닌 업데이트

 

 - 테이블 / 데이터 처리 명령어

  Table Data
Create create insert
Read desc select
Update alter update
Delete drop delete

 

 - 기타 참고사항

    * 명령어는 대소문자를 구분하지 않음

    * [] 안의 내용은 생략이 가능

    * Oracle은 utf-8로 작성. 영문자 1byte, 한글 3bytes



 

2. JDBC

 

 - JDBC : Java DataBase Connectivity

    자바에서 데이터베이스에 접속할 수 있도록 하는 자바 API

 

 - JFrame과 JDBC를 활용하여 사내 직원 정보 입력/수정/삭제/조회/검색 기능 구현

 

// 데이터 한 건(1 row)에 대한 정보를 가지는 클래스
public class DeptVo { 
	// VO(Value Object): Java Bean으로 작성
	/* Java Bean: 특정한 정보(id, password, name etc)를 가지고 있는 클래스를 표현하는 하나의 규칙
	 * 데이터를 표현하기 위한 목적을 가짐
	 * 이러한 규칙을 지닌 클래스 -> Java Bean
	 * Java Bean의 몇가지 규약을 지켜서 작성해야 함(멤버변수 private 지정, 외부 접근을 위한 getter setter 메소드 정의 등) 
	*/
	private int deptno;
	private String dname;
	private String loc;

	public DeptVo() { super(); }

	public DeptVo(int deptno, String dname, String loc) {
		super();
		this.deptno = deptno;
		this.dname = dname;
		this.loc = loc;
	}

	public int getDeptno() {
		return deptno;
	}

	public void setDeptno(int deptno) {
		this.deptno = deptno;
	}

	public String getDname() {
		return dname;
	}

	public void setDname(String dname) {
		this.dname = dname;
	}

	public String getLoc() {
		return loc;
	}

	public void setLoc(String loc) {
		this.loc = loc;
	}

	@Override
	public String toString() {
		return "DeptVo [deptno=" + deptno + ", dname=" + dname + ", loc=" + loc + "]";
	}
}

 

// 데이터베이스에 접근(데이터베이스 담당자)하는 클래스
public class DeptDao { // DAO(Data Access Object)
	// <참고> ctrl + shift + x : 대문자로 변경 / ctrl + shift + y : 소문자로 변경
	// 데이터베이스 접근을 위한 변수(id, pw, driver, url)는 private final로 정의해야 함
	private final String ID = "user01"; 
	private final String PW = "1234"; // ID & PW: Oracle에서 미리 설정해 놓은 user의 정보
	private final String DRIVER = "oracle.jdbc.driver.OracleDriver";
	private final String URL = "jdbc:oracle:thin:@localhost:1521:xe"; // localhost -> ip부분
	
	// 싱글톤(담당자만 접근하도록 해야 함)
	private static DeptDao instance = new DeptDao();
	
	private DeptDao() {/* Singleton */}
	
	public static DeptDao getInstance() {
		return instance;
	}
	
	// 커넥션 얻기
	private Connection getConnection() {
		try {
			Class.forName(DRIVER); // driver 이름을 잘못 입력할 수도 있기 때문에 발생하는 오류 처리 필요
			Connection conn = DriverManager.getConnection(URL, ID, PW);
			return conn;
		} catch (Exception e) { 
			e.printStackTrace();
		}
		return null; // 참조형의 기본값 null(문제 발생 시 conn이 아닌 null 반환)
	}
	
	// CRUD 작업에서 공통적으로 필요한 메서드(close) 만들기
	// 예외처리가 필요해 코드가 복잡해질 수 있으니 따로 메서드를 만드는 것
	private void closeAll(Connection conn, PreparedStatement pstmt, ResultSet rs) {
		if (rs != null) try { rs.close(); } catch (Exception e) {}
		if (pstmt != null) try { rs.close(); } catch (Exception e) {}
		if (conn != null) try { rs.close(); } catch (Exception e) {}
	}
	
	// 데이터 입력
	public boolean insert(DeptVo vo) { // 입력이 잘 되었는지 확인을 위해 boolean 타입 사용
		Connection conn = null;
		PreparedStatement pstmt = null; // 데이터 입력을 위해 필요한 Connection, PreparedStatement
		
		try {
			conn = getConnection(); // 접속하기
			String sql = "insert into dept01" // 실행할 문장 만들기
						+ " (deptno, dname, loc)" // 앞에 띄어쓰기가 없으면 dept01deptno 이런식으로 작성돼 에러 발생
						+ " values (?, ?, ?)"; // 값 3개가 들어가는 것 표현. ;는 자동으로 추가됨
			pstmt = conn.prepareStatement(sql); // 문장을 실행할 pstmt 얻기
			pstmt.setInt(1, vo.getDeptno()); // 첫번째 물음표의 값 설정
			pstmt.setString(2, vo.getDname()); // setString을 사용하면 ''를 자동으로 설정해줌
			pstmt.setString(3, vo.getLoc());
			int count = pstmt.executeUpdate();
			/* executeUpdate: select문을 제외한 다른 구문(insert, update, delete)을 실행할 때 사용하는 함수
			 * 몇개의 행에 변경사항이 있는지에 대한 값 반환(변경이 적용된 기록 건수 반환) */
			if (count == 1) { // count > 0 으로 작성해도 됨(메서드가 제대로 실행된다면 최소 1건 이상이 변경될 것이기 때문)
				return true;
			}
		} catch (Exception e) {
			e.printStackTrace(); // 연습단계라 예외는 간단하게 처리함
		} finally {
			closeAll(conn, pstmt, null); // 이 메서드에서 ResultSet은 사용되지 않았으므로 null로 작성
		}
		return false; // 입력이 제대로 되지 않았을 때 false 반환
	}
	
	// 데이터 수정
	public boolean update(DeptVo vo) { // 수정이 잘 되었는지 확인을 위해 boolean 타입 사용
		Connection conn = null;
		PreparedStatement pstmt = null;
		
		try {
			conn = getConnection();
			String sql = "update dept01 set"
						+ " dname = ?,"
						+ " loc = ?"
						+ " where deptno = ?";
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, vo.getDname());
			pstmt.setString(2, vo.getLoc());
			pstmt.setInt(3, vo.getDeptno());
			int count = pstmt.executeUpdate();
			if (count > 0) {
				return true;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			closeAll(conn, pstmt, null);
		}
		return false;
	}
	
	// 데이터 삭제
	public boolean delete(int deptno) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		
		try {
			conn = getConnection();
			String sql = "delete dept01"
						+ " where deptno = ?";
			pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1, deptno);
			int count = pstmt.executeUpdate();
			if (count > 0) {
				return true;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			closeAll(conn, pstmt, null);
		}
		return false;
	}
	
	// 데이터 조회
	public Vector<DeptVo> selectAll() {
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null; // 데이터를 조회하려면 결과를 담을 ResultSet 필요
		
		try {
			conn = getConnection();
			String sql = "select *"
						+ " from dept01"
						+ " order by deptno";
			pstmt = conn.prepareStatement(sql);
			rs = pstmt.executeQuery(); // executeupdate가 아님. executeQuery: select문을 실행할 때 사용하는 함수
			Vector<DeptVo> vec = new Vector<>();
			while (rs.next()) { // 다음에 읽을 행이 있다면 true, 아니면 false 반환
				int deptno = rs.getInt("deptno");
				String dname = rs.getString("dname");
				String loc = rs.getString("loc"); // deptno, dname, loc이 데이터 한 건
				
				DeptVo vo = new DeptVo(deptno, dname, loc);
				vec.add(vo); // 데이터들을 담을 공간
			}
			return vec; // while문 안에 작성하지 않도록 주의
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			closeAll(conn, pstmt, rs);
		}
		return null;
	}
	
	// 데이터 검색
	public Vector<DeptVo> search(String col, String keyword) { // 파라미터: 컬럼, 검색어
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			conn = getConnection();
			String sql = "select * from dept01"
						+ " where " + col + " like '%" + keyword + "%'"; // 검색 옵션과 검색어가 필요함
			/* col을 ?를 쓰면 쿼리가 자동으로 ''을 추가해서 에러 발생
			 * sql 부분 띄어쓰기 주의!!!!!! */
			System.out.println(sql);
			pstmt = conn.prepareStatement(sql);
			rs = pstmt.executeQuery();
			Vector<DeptVo> vec = new Vector<>();
			while (rs.next()) {
				int deptno = rs.getInt("deptno");
				String dname = rs.getString("dname");
				String loc = rs.getString("loc");
				
				DeptVo vo = new DeptVo(deptno, dname, loc);
				vec.add(vo);
			}
			return vec;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			closeAll(conn, pstmt, rs);
		}
		return null;
	}
}

 

public class DeptFrame extends JFrame implements ActionListener {
	DeptDao dao;
	Container c = getContentPane();
	InputDialog dialog = new InputDialog();
	JButton btnInsert = new JButton("입력");
	JButton btnUpdate = new JButton("수정");
	JButton btnDelete = new JButton("삭제");
	JButton btnSelect = new JButton("조회");
	JButton btnSearch = new JButton("검색");
	JComboBox<String> cbSearch = new JComboBox<>(new String[] {
			"부서번호", "부서명", "지역"
	});
	JTextField tfSearch = new JTextField(10);
	JTextArea taResult = new JTextArea();
	
	public DeptFrame(DeptDao dao) {
		this.dao = dao;
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setTitle("부서 정보");
		setSize(600, 500);
		setUI();
		setListener();
		setVisible(true);
	}
	
	private void setListener() {
		btnInsert.addActionListener(this);
		btnUpdate.addActionListener(this);
		btnDelete.addActionListener(this);
		btnSelect.addActionListener(this);
		btnSearch.addActionListener(this);
		tfSearch.addActionListener(this);
	}

	private void setUI() {
		JPanel panel = new JPanel();
		panel.setBackground(Color.YELLOW);
		panel.add(btnInsert);
		panel.add(btnUpdate);
		panel.add(btnDelete);
		panel.add(btnSelect);
		panel.add(cbSearch);
		panel.add(tfSearch);
		panel.add(btnSearch);
		panel.add(taResult);
	
		c.add(panel, BorderLayout.NORTH);
		c.add(new JScrollPane(taResult));
	}

	public static void main(String[] args) {
		new DeptFrame(DeptDao.getInstance());
        // 전략패턴: 어떤 파라미터를 쓸 지 메인에서 결정함
		// 프레임에서 얻어도 결과는 동일함(사용하는 패턴이 다른 것 뿐)
	}
	
	private void showResult(Vector<DeptVo> vec) { // search와 select에서 반복되는 작업이라 메서드 처리
		taResult.setText("");
		for (DeptVo vo : vec) {
			StringBuffer sb = new StringBuffer();
			sb.append(vo.getDeptno()); sb.append(" | ");
			sb.append(vo.getDname()); sb.append(" | ");
			sb.append(vo.getLoc()); sb.append("\n");
			taResult.append(sb.toString());
		}
	}
	
	public class InputDialog extends JDialog implements ActionListener { // 데이터 입력 시 사용할 팝업창
		JTextField tfDeptno = new JTextField();
		JTextField tfDname = new JTextField();
		JTextField tfLoc = new JTextField();
		JButton btnOk = new JButton("확인");
		JButton btnCancel = new JButton("취소");
		
		public InputDialog() {
			setModal(true); // 다이얼로그 창을 처리하지 않으면 다른 작업을 실행하지 못하도록 설정
			setLayout(new GridLayout(4, 2));
			setTitle("입력");
			setSize(300, 200);
			this.setUI();
			this.setListener();
		}

		private void setListener() {
			btnOk.addActionListener(this);
			btnCancel.addActionListener(this);
		}

		private void setUI() {
			add(new JLabel("부서번호:"));
			add(tfDeptno);
			add(new JLabel("부서명:"));
			add(tfDname);
			add(new JLabel("지역:"));
			add(tfLoc);
			add(btnOk);
			add(btnCancel);
		}

		@Override
		public void actionPerformed(ActionEvent e) { // 다이얼로그 액션 처리
			Object obj = e.getSource();
			if (obj == btnOk) {
				String title = getTitle(); // 입력/수정에 따라 다른 작업 처리를 위함
				
				int deptno = Integer.parseInt(tfDeptno.getText());
				String dname = tfDname.getText();
				String loc = tfLoc.getText();
				
				DeptVo vo = new DeptVo(deptno, dname, loc);
				
				boolean result = false;
				
				if (title.equals("입력")) result = dao.insert(vo);
				else if (title.equals("수정")) result = dao.update(vo);
				
				if (result) JOptionPane.showMessageDialog(this, title + " 성공", 
						"결과", JOptionPane.DEFAULT_OPTION);
				else JOptionPane.showMessageDialog(this, title + " 실패", 
						"결과", JOptionPane.DEFAULT_OPTION);
				setVisible(false);
			} else if (obj == btnCancel) {
				setVisible(false);
			}
		}
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		Object obj = e.getSource();
		if (obj == btnInsert) {
			dialog.setTitle("입력");
			dialog.setVisible(true);
		} else if (obj == btnUpdate) {
			dialog.setTitle("수정");
			dialog.setVisible(true);
		} else if (obj == btnDelete) {
			String input = JOptionPane.showInputDialog(this, 
								"삭제할 부서번호를 입력하세요.", "삭제", 
								JOptionPane.QUESTION_MESSAGE);
			int deptno = Integer.parseInt(input);
			boolean result = dao.delete(deptno);
			String message = "";
			if (result) {
				message = "삭제 성공";
			} else {
				message = "삭제 실패";
			}
			JOptionPane.showMessageDialog(this, message, 
								"삭제 결과", JOptionPane.DEFAULT_OPTION);
		} else if (obj == btnSelect) {
			Vector<DeptVo> vec = dao.selectAll();
			showResult(vec);
		} else if (obj == btnSearch || obj == tfSearch) {
			String item = (String)cbSearch.getSelectedItem(); // 콤보박스에서 선택된 글자 얻기
			String col = "";
			switch (item) {
			case "부서번호" :
				col = "deptno";
				break;
			case "부서명" :
				col = "dname";
				break;
			case "지역" :
				col = "loc";
				break;
			}
			String keyword = tfSearch.getText();
			Vector<DeptVo> vec = dao.search(col, keyword);
			showResult(vec);
		}
	}
}

 

// 테스트 코드
public class DeptDaoTest {
	private static DeptDao dao = DeptDao.getInstance();
	
	public static void main(String[] args) {
//		testInsert(); // Oracle에서 조회해보면 DeptVo 생성자의 파라미터 값이 들어가 있음
//		testUpdate();
//		testDelete();
//		insertTestData();
//		testSelectAll();
		testSearch();
	}
	
	private static void testInsert() {
		DeptVo vo = new DeptVo(10, "경리부", "서울"); // 실제로는 사용자에게 입력을 받겠지만 테스트를 위해 임의로 생성
		boolean result = dao.insert(vo);
		System.out.println(result);
	}
	
	private static void testUpdate() {
		DeptVo vo = new DeptVo(10, "인사부", "부산");
		boolean result = dao.update(vo);
		System.out.println(result);
	}
	
	private static void testDelete() {
		int deptno = 10;
		boolean result = dao.delete(deptno);
		System.out.println(result);
	}
	
	private static void insertTestData() { // 미리 데이터를 입력해놓고 테스트하면 편하게 코드를 작성할 수 있음
		for (int i = 1; i < 10; i++) {
			DeptVo vo = new DeptVo(10 * i, "경리부" + i, "서울" + i);
			boolean result = dao.insert(vo);
			System.out.println(result);
		}
	}
	
	private static void testSelectAll() {
		Vector<DeptVo> vec = dao.selectAll();
		System.out.println(vec); // DeptVo에서 toString을 오버라이딩하여 원하는 형식으로 출력됨
	}
	
	private static void testSearch() {
		Vector<DeptVo> vec = dao.search("dname", "부7");
		System.out.println(vec);
	}
}

'Daily Record' 카테고리의 다른 글

[JDBC/활용] SQL과 JFrame으로 CRUD 구현하기  (0) 2023.05.22
5월 3주차 학습 내용 정리  (0) 2023.05.20
5월 11일 학습 내용 정리  (0) 2023.05.11
5월 10일 학습 내용 정리  (0) 2023.05.10
5월 9일 학습 내용 정리  (0) 2023.05.09
Contents

Copied URL!

Liked this Posting!