[JDBC]TIL(Today I Learned)_230816

Aspyn Choi·2023년 8월 16일
0

TIL

목록 보기
23/37

☝🏻오늘 배운 것

1. XML 파일

- XML(eXtensible Markup Language)

  • 단순화된 데이터 기술 형식이라는 뜻
  • XML에 저장되는 데이터 형식은 Key : Value로 저장되는 map형식이며, key, value 모두 String 형식이다.

2. Properties

- Properties Class

  • Map의 후손 클래스
  • XML 파일을 읽고, 쓰기위한 IO 관련 클래스
  • Key : Value 값은 모두 String 형식이다
  • XML 파일을 읽고, 쓰는데에 특화된 메서드 제공
  • key를 주면 Value를 반환하는 기능을 가지며, DB의 연결정보 등을 저장해두는 용도로 많이 쓰임

3. storeToXML

  • 데이터를 XML 형식으로 저장하는 데 사용되는 메서드 또는 함수

4. Class 세분화 하기

- CreateXMLFile Class

package edu.kh.jdbc.common;

import java.io.FileOutputStream;
import java.util.Properties;
import java.util.Scanner;

public class CreateXMLFile {

	public static void main(String[] args) {
		
		try {
			
			Scanner sc = new Scanner(System.in);
			
			// Properties 객체 생성
			Properties prop = new Properties();
			
			System.out.print("생성할 파일 이름 : ");
			String fileName = sc.nextLine();
			
			// FileOutputStream 생성
			FileOutputStream fos = new FileOutputStream(fileName + ".xml");
			
			// Properties 객체를 이용해 xml파일 생성
            // prop에 저장된 데이터를 XML형식으로 파일에 저장
			prop.storeToXML(fos, fileName);			
			
			System.out.println(fileName + ".xml 파일 생성 완료");
			
		}catch(Exception e) {
			
			e.printStackTrace();
		}		
	}
}

- LoadeXMLFile Class

package edu.kh.jdbc.common;

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;

public class LoadeXMLFile {
	
	public static void main(String[] args) {
		
		// XML 파일 읽어오기 (Properties, InputStream)
		
		try {
			
			Properties prop = new Properties();
			
			// driver.xml파일을 읽어오기 위한 inputStream 객체 생성
			FileInputStream fis = new FileInputStream("test-query.xml");
			
			// 연결된 driver.xml 파일에 있는 내용을 모두 읽어와
			// Properties 객체에 k:v 형식으로 저장
			prop.loadFromXML(fis);
			
			System.out.println(prop);
			
			
			// prop.getProperty("key"); key가 일치하는 value(속성)을 얻어옴
			String driver = prop.getProperty("driver");
			String url = prop.getProperty("url");
			String user = prop.getProperty("user");
			String password = prop.getProperty("password");
			
			Class.forName(driver);
			
			Connection conn = DriverManager.getConnection(url, user, password);
			
			System.out.println(conn);
			
			/*
			 * 왜 XML 파일을 이용해서 DB연결 정보를 읽어와야할까?
			 * 
			 * 1. 코드 중복 제거
			 * 2. 별도 관리 용도
			 * 3. 재 컴파일을 진행하지 않기 위해서
			 * 		- 코드가 길수록 컴파일에 소요되는 시간이 크다
			 * 		-> 코드 수정으로 인한 컴파일 소요시간을 없앰
			 * 		(파일의 내용을 읽어오는 코드만 작성해두면 
			 * 		Java 코드 수정 없이, 파일 내용만 수정하면
			 * 		재컴파일은 수행되지 않는다)
			 * 
			 * 4. XML 파일에 작성된 문자열 형태를 그대로 읽어오기 때문에
			 * 		SQL 작성 시 좀 더 편리해진다.
			 */
			
			
		}catch(Exception e ) {
			e.printStackTrace();
		}
	}
}

- JDBCTemplete Class

package edu.kh.jdbc.common;

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;

public class JDBCTemplete {
	
	/* DB 연결(Connection 생성), 자동 커밋 off
	 * 트랜잭션 제어, JDBC 객체 자원 반환(close)
	 * 
	 * 이러한 JDBC에서 반복 사용되는 코드를 모아둔 클래스
	 * 
	 * * 모든 필드, 메서드가 static *
	 * -> 별도 객체 생성 필요없이
	 * -> 어디서든지 클래스명.필드명 / 클래스명.메서드명 으로 호출 가능
	 * 
	 */
	
	private static Connection conn = null;

	/** DB 연결정보를 담고있는 Connection 객체 생성 및 반환 메서드
	 * @return conn
	 */
	public static Connection getConnection() { 
		
		try {
			
			// 현재 커넥션 객체가 없을 경우 -> 새 커넥션 객체 생성
			if(conn == null || conn.isClosed()) {
				// conn.isClosed() : 커넥션이 close 상태이면 true 반환
				
				Properties prop = new Properties();
				// Map<String, String> 형태의 객체, XML 입출력에 특화
	
				// driver.xml 파일 읽어오기
				prop.loadFromXML( new FileInputStream("driver.xml") );
				// -> XML 파일에 작성된 내용이 Properties 객체에 모두 저장됨
				
				// XML에서 읽어온 값을 모두 변수에 저장
				String driver = prop.getProperty("driver");
				String url = prop.getProperty("url");
				String user = prop.getProperty("user");
				String password = prop.getProperty("password");
				
				// 커넥션 생성
				Class.forName(driver);
				
				// DriverManager를 이용해 Connectioin 객체 생성
				conn = DriverManager.getConnection(url, user, password);
				
				// 자동 커밋 비활성화
				conn.setAutoCommit(false);
			
			}
			
		}catch(Exception e) {
			System.err.println("[Connection 생성 중 예외 발생]");
			e.printStackTrace();
			
		}
		
		return conn;
	
	}
	
	
	/** Connection 객체 자원 반환 메서드
	 * @param conn
	 */
	public static void close(Connection conn){
		
		try {
			// 전달받은 conn이 참조하는 Connection 객체가 있고 그 Connection 객체가 close 상태가 아니라면
			if(conn != null && !conn.isClosed()) conn.close();
			
		}catch(Exception e) {
			e.printStackTrace();
		}
		
	}
	
	/** Statement(부모), PreparedStatement(자식) 객체 자원 반환 메서드
	 * @param stmt
	 */
	public static void close(Statement stmt) {
		
		try {
			if(stmt != null && !stmt.isClosed()) stmt.close();
			
		}catch(Exception e) {
			e.printStackTrace();
		}
		
	}
	
	/** ResultSet 객체 자원 반환 메서드
	 * @param rs
	 */
	public static void close(ResultSet rs) {
		
		try {
			if(rs != null && !rs.isClosed()) rs.close();
			
		}catch(Exception e) {
			e.printStackTrace();
		}
		
	}
	
	
	/** 트랜젝션 Commit 메서드
	 * @param conn
	 */
	public static void commit(Connection conn) {
		
		try {
			
			if(conn != null && !conn.isClosed()) conn.commit();
			
		}catch(Exception e) {
			e.printStackTrace();
		}
		
	}
	
	/** 트랜젝션 Rollback 메서드
	 * @param conn
	 */
	public static void rollback(Connection conn) {
		
		try {
			
			if(conn != null && !conn.isClosed()) conn.rollback();
			
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
}

- driver.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>

	<comment>driver</comment>
	
	<!-- 마크업 언어 주석 -->
	<!-- ctrl + shift + / -->
	
	<!-- entry : k:v 한 쌍 -->
	<entry key= "driver">oracle.jdbc.driver.OracleDriver</entry>
	<entry key = "url">jdbc:oracle:thin:@localhost:1521:XE</entry>
	<entry key = "user">kh</entry>
	<entry key = "password">kh1234</entry>


</properties>

- test-query.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
	<comment>test-query</comment>
	
	<entry key = "insert">
		INSERT INTO TB_TEST
		VALUES(?, ?, ?)
	</entry>
	
	
</properties>

5. insert 실습예제

- TestVO Clas

package edu.kh.jdbc.model.vo;

public class TestVO {
	
	private int testNo;
	private String testTitle;
	private String testContent;

	public TestVO() {}
	
	public TestVO(int testNo, String testTitle, String testContent) {
		this.testNo = testNo;
		this.testTitle = testTitle;
		this.testContent = testContent;
	}

	public int getTestNo() {
		return testNo;
	}

	public void setTestNo(int testNo) {
		this.testNo = testNo;
	}

	public String getTestTitle() {
		return testTitle;
	}

	public void setTestTitle(String testTitle) {
		this.testTitle = testTitle;
	}

	public String getTestContent() {
		return testContent;
	}

	public void setTestContent(String testContent) {
		this.testContent = testContent;
	}

	
	@Override
	public String toString() {
		return "TestVO [testNo=" + testNo + ", testTitle=" + testTitle + ", testContent=" + testContent + "]";
	}
}

- Run Clas

package edu.kh.jdbc.run;

import java.sql.SQLException;

import edu.kh.jdbc.model.service.TestService;
import edu.kh.jdbc.model.vo.TestVO;

public class Run {
	
	public static void main(String[] args) {
		
		TestService service = new TestService();
		
		// TB_TEST 테이블에 INSERT 수행
		TestVO vo1 = new TestVO(1, "제목1", "내용1");
		
		// TB_TEST 테이블에 INSERT를 수행하는 서비스 메서드를 호출 후 결과 반환받기
		
		try {
			int result = service.insert(vo1); // 1 / 0
			if(result > 0) {
				System.out.println("insert 성공");
			}else {
				System.out.println("insert 실패");
			}
		}catch(SQLException e) {
			System.out.println("SQL수행 중 오류 발생");
			e.printStackTrace();
		}
		
	}

}

- Run2 Clas

package edu.kh.jdbc.run;

import edu.kh.jdbc.model.service.TestService;
import edu.kh.jdbc.model.vo.TestVO;

public class Run2 {

	public static void main(String[] args) {
		
		// TB_TEST 테이블에 한번에 3행 삽입
		TestService service = new TestService();
		
		TestVO vo1 = new TestVO(70, "제목70", "내용70");
		TestVO vo2 = new TestVO(80, "제목80", "내용80");
		TestVO vo3 = new TestVO(90, "제목90", "내용90");
		
		try {
			
			int result = service.insert(vo1, vo2, vo3);
			if(result > 0) {
				System.out.println("insert 성공");
			}else {
				System.out.println("insert 실패");
			}
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
}

- TestService Clas

package edu.kh.jdbc.model.service;

import java.sql.Connection;
import java.sql.SQLException;

// import static 구문
// -> static이 붙은 필드, 메서드를 호출할 때
// 		클래스명을 생략할 수 있게해주는 구문
import static edu.kh.jdbc.common.JDBCTemplete.*;

import edu.kh.jdbc.model.dao.TestDAO;
import edu.kh.jdbc.model.vo.TestVO;

public class TestService {
	// Service : 비즈니스 로직(데이터 가공, 트랜잭션 제어) 처리
	// -> 실제 프로그램이 제공하는 기능을 모아둔 클래스
	
	// 하나의 Service 메서드에서 n개의 DAO 메서드를 호출하여
	// 이를 하나의 트랜잭션 단위로 취급하여
	// 한번에 commit, rollback을 수행할 수 있다.

	private TestDAO dao = new TestDAO();
	
	public int insert(TestVO vo1) throws SQLException {
		
		// 커넥션 생성
		Connection conn = getConnection();
		
		// DAO 메서드 호출하여 수행 후 결과 반환받기
		// -> Service 에서 생성한 Connection 객체를 반드시 같이 전달!
		int result = dao.insert(conn, vo1);
		
		// 트랜잭션 제어
		if(result > 0) commit(conn);
		else 			rollback(conn);
		
		// 커넥션 반환
		close(conn);
		
		// 결과 반환
		return result;
		
	}

	/** 3행 삽입 서비스
	 * @param vo1
	 * @param vo2
	 * @param vo3
	 * @return result
	 */
	public int insert(TestVO vo1, TestVO vo2, TestVO vo3) {
		
		Connection conn = getConnection();
		
		int result = 0; // insert 3회 성공 시 1, 아니면 0
		
		try {
			
			int res1 = dao.insert(conn, vo1);
			int res2 = dao.insert(conn, vo2);
			int res3 = dao.insert(conn, vo3);
			
			if(res1 + res2 + res3 == 3) { // 모두 insert 성공한 경우
				commit(conn);
				result = 1;
			}else {
				rollback(conn);
			}
			
		}catch(Exception e ) {
			e.printStackTrace();
		}
		
		return result;
	}
}

- TestDAO Clas

package edu.kh.jdbc.model.dao;

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

import edu.kh.jdbc.model.vo.TestVO;
import static edu.kh.jdbc.common.JDBCTemplete.*;

public class TestDAO {
	// DAO (Data Access Object) : 데이터가 저장된 DB에 접근하는 객체
	//							-> SQL을 수행, 결과를 반환받는 기능 수행
	
	// JDBC 객체를 참조하기 위한 참조변수 선언
	private Statement stmt;
	private PreparedStatement pstmt;
	private ResultSet rs;
	
	// XML로 SQL을 다룰것이다 -> Properties 객체 사용
	private Properties prop;
	
	// 기본생성자
	public TestDAO() {
		// TestDAO 객체 생성시
		// test-query.xml 파일의 내용을 읽어와
		// Properties 객체에 저장
		
		try {
			prop = new Properties();
			prop.loadFromXML(new FileInputStream("test-query.xml"));
		}catch(Exception e ) {
			e.printStackTrace();
		}
	}
	

	public int insert(Connection conn, TestVO vo1) throws SQLException{

		// 1. 결과 저장용 변수 선언
		int result = 0;
		
		try {
			
			// 2. SQL 작성(test-query.xml에 작성된 SQL 얻어오기)
			String sql = prop.getProperty("insert");
			
			// 3. PreparedStatement 객체 생성
			pstmt = conn.prepareStatement(sql);
			
			// 4. 위치 홀더(?)에 알맞은 값 셋팅
			pstmt.setInt(1, vo1.getTestNo());
			pstmt.setString(2, vo1.getTestTitle());
			pstmt.setString(3, vo1.getTestContent());
			
			
			// 5. SQL(INSERT) 수행 후 결과 반환받기
			result = pstmt.executeUpdate(); // -> DML을 수행, 반영된 행의 개수(int) 반환
			
		}finally {
			// 6. 사용한 JDBC 객체 자원 반환
			close(pstmt);
			
		}
		
		// 7. SQL 수행 결과 반환
		return result;
	}
}

0개의 댓글