Java: JDBC

0
post-thumbnail

JDBC를 사용하기 위해, 크게 1+3 클래스 구조를 사용한다고 하였다.

여기에 비즈니스 로직을 처리하는 클래스 하나를 더하여 1+4로 구성되는 것이 일반적이다.


구조와 역할

  • Main은 모든 클래스의 객체 생성 및 단위 기능의 실행을 담당한다
  • ConnectionManager Class는 DAO가 DB에 접근할 수 있는 연결 메소드를 제공한다
    • driver / jdbcURL / 데이터베이스 계정 및 비밀번호
      DriverManager.getConnection(jdbcURL, id, pwd)로 Connection 생성
  • Business Class는 DAO에 ResultSet을 요청하며 이를 토대로 연산작업을 수행한다

  • DAO는 ConnectionManager Class의 Connection을 사용하여 쿼리를 실행하고 ResultSet을 반환 받는다

    1. Query 작성
    2. ConnectionManager.getConnection()으로 DB에 연결
    3. connection의 Statement(sql)을 사용하여 통로 확보
    4. 확보한 통로에서 execute() 관련 메서드를 사용하여 ResultSet 확보
    5. ResultSet을 적절히 전처리하여 return -> Business Class에서 연산을 위한 데이터로 사용
  • VO는 다른 클래스에서 필요한 필드값을 제공하거나 간접적으로 데이터 처리에 관여한다


ConnectionManager 예제

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class ConnectionManager {
	
	public static Connection getConnection() {
		String driver = "org.mariadb.jdbc.Driver";
		String jdbcURL = "jdbc:mariadb://127.0.0.1:3306/sample";
		String id = "user";
		String pwd = "1234";
		Connection con = null;
		
		try {
			Class.forName(driver);
			try {
				con = DriverManager.getConnection(jdbcURL, id, pwd);
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return con;
	}/* getConnection() */
	
	
	public static void closeConnection(ResultSet rs, Statement stmt, Connection con) {
		if(rs!=null) {
			try {
				rs.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}//end rs if
		
		if(stmt != null) {
			try {
				stmt.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}//end stmt if
		
		if(con != null) {
			try {
				con.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}/* closeConnection */
}

정형화된 코드이며 로직은 존재하지 않는다. 넣어서 쓰기만 하면 된다.


DAO 예제

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

public class DAO {
	
	public ArrayList<VO> getData03(int score) throws SQLException{
		String sql = "select * from gisa where eng+math >= ?";
		ArrayList<VO> list = new ArrayList<VO>();
		
		Connection con = ConnectionManager.getConnection();
		PreparedStatement pstmt = con.prepareStatement(sql);
		pstmt.setInt(1, score);
		ResultSet rs = pstmt.executeQuery();
		
		while(rs.next()) {
			VO vo = new VO(rs.getInt(1), rs.getString(2), rs.getInt(3), rs.getInt(4)
					, rs.getInt(5), rs.getInt(6), rs.getInt(7), rs.getInt(8), rs.getString(9), rs.getString(10), rs.getString(11));
			list.add(vo);
		}
		ConnectionManager.closeConnection(rs, pstmt, con);
		
		return list;
	}/* getData03() */
	
	
	public ArrayList<VO> getData01(String code) throws SQLException {
		String sql = "select * from gisa where loccode = ?";
		ArrayList<VO> list = new ArrayList<VO>();
		
		// 연결 
		Connection con = ConnectionManager.getConnection();
		
		// 통로 
		PreparedStatement pstmt = con.prepareStatement(sql);
		pstmt.setString(1, code);
		
		// 쿼리 전송 및 반환 
		ResultSet rs = pstmt.executeQuery();
		
		// 결과셋 정제 
		VO vo = null;
		while(rs.next()) {
			vo = new VO(rs.getInt(1), rs.getString(2), rs.getInt(3), rs.getInt(4) 
						,rs.getInt(5), rs.getInt(6), rs.getInt(7), rs.getInt(8), rs.getString(9), rs.getString(10), rs.getString(11));
			list.add(vo);
		}
		ConnectionManager.closeConnection(rs, pstmt, con);
		
		return list;
	}/* getData01() */
	
}/* END OF DAO */

쿼리를 보내는 과정은, 마찬가지로 정형화되어 있다.
결과셋을 받는 방법에 어떤 다양한 방식이 있는지는 아직까지 경험이 부족하다.

단순히 쿼리셋으로 해결 가능한 Business Logic이 있는 반면,
쿼리를 통해 결과셋을 가져오고 이를 Logic으로 정제하여 해결하는 상황도 있을 것이다.
선택 사용.


Business Class 예제

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;

public class Service {
	
	public void solution03() {
		DAO dao = new DAO();
		try {
			ArrayList<VO> list = dao.getData03(120);
			int total = 0;
			for(VO vo : list) {
				int point = 20;
				if(vo.getMgrCode().equals("A")) {
					point = 5;
				}else if(vo.getMgrCode().equals("B")) {
					point = 15;
				}
				total = total + vo.getTotal() + point;
			}//end for
		System.out.println("The total score is... "+total);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}/* solution03() */
	
	
	public void solution01() {
		/* DAO에 ResultSet 요청 */
		DAO dao = new DAO();
		try {
			ArrayList<VO> list = dao.getData01("B");
			
		/* 받은 ResultSet으로 문제 해결 */
			Collections.sort(list, new Comparator());
			System.out.println("fifth's StudentNo is... "+list.get(4).getStdNo());
			
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}/* solution01() */
}/* END OF BUISNESS CLASS */

제공하려는 서비스가 무엇인지에 따라 코드 내용이 천차만별이다.
앞선 클래스들과의 흐름 속에서, 여기 코드는 이런 식으로 처리했구나 정도로 보면 될 것 같다.


VO 예제

public class VO {
	/* field */
	private int stdNo;
	private String email;
	private int kor;
	private int eng;
	private int math;
	private int sci;
	private int hist;
	private int total;
	private String accCode;
	private String mgrCode;
	private String locCode;
	
	public VO(int stdNo, String email, int kor, int eng, int math, int sci, int hist, int total,
			String accCode, String mgrCode, String locCode) {
		this.stdNo = stdNo;
		this.email = email;
		this.kor = kor;
		this.eng = eng;
		this.math = math;
		this.sci = sci;
		this.hist = hist;
		this.total = total;
		this.accCode = accCode;
		this.mgrCode = mgrCode;
		this.locCode = locCode;
	}/* end constructor */


	public int getStdNo() {
		return stdNo;
	}

	public void setStdNo(int stdNo) {
		this.stdNo = stdNo;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public int getKor() {
		return kor;
	}

	public void setKor(int kor) {
		this.kor = kor;
	}

	public int getEng() {
		return eng;
	}

	public void setEng(int eng) {
		this.eng = eng;
	}

	public int getMath() {
		return math;
	}

	public void setMath(int math) {
		this.math = math;
	}

	public int getSci() {
		return sci;
	}

	public void setSci(int sci) {
		this.sci = sci;
	}

	public int getHist() {
		return hist;
	}

	public void setHist(int hist) {
		this.hist = hist;
	}
	
	public int getTotal() {
		return total;
	}

	public void setTotal(int total) {
		this.total = total;
	}

	public String getAccCode() {
		return accCode;
	}

	public void setAccCode(String accCode) {
		this.accCode = accCode;
	}

	public String getMgrCode() {
		return mgrCode;
	}

	public void setMgrCode(String mgrCode) {
		this.mgrCode = mgrCode;
	}

	public String getLocCode() {
		return locCode;
	}

	public void setLocCode(String locCode) {
		this.locCode = locCode;
	}/* end Getter Setter */
	
	public int getData01() {
		return this.kor + this.eng;
	}
	
}/* END OF VO */

데이터가 가진 속성값을 정의하고 필요한 값을 가져오거나 세팅할 수 있도록 정보를 제공하는 클래스다.
관련된 메서드를 편하게 만들 수 있는 기능을 IDE에서 풍부하게 제공한다.
생성자에서 모든 필드값을 파라미터로 받아 처리하는 모습을 볼 수 있다.
만약 값의 개수가 더 늘어난다면 어떻게 처리할지 궁금하다.


정리

아직 Spring을 사용하지 않았지만, 지금까지만 봐도 django와 그 구조가 닮아있다.
Model과 VO / DAO + BusinessClass는 View
django에서는 View가 Controller 역할도 하기에 좀 더 압축된 느낌(?)이 있는 것 같다.
너무 초반이라 어떤 것들이 또 튀어나올지는 모르겠다.

오늘 내용까지 이해한 것에 감사한다.

0개의 댓글