-
JDBC-22.06.21웹프로그래밍 2022. 6. 22. 00:17728x90
DB에 대한 종속성을 없애야함
1. 어떤 DB여도 사용할 수 있게 추상화된 인터페이스 필요하다.
2. 명령어 서로 다름(DB마다) 쿼리 객체 필요 일관된 인터페이스 필요하다.
3. 쿼리 실행 방법론 인터페이스 필요
이모든게 rt.jar안에 java- sql에 존재한다.
드라이버 구현체는 제조사가 지원해준다. => Facade객체(실객체가 따로있고 실객체에 명령을 전달해주는 객체. ex리모콘)
pom.xml 추가하기 (벤더가 제공하는 드라이버 빌드패스에 추가)
프로시저: 반환값 존재 x
JavaDataBaseConnectivity - JDBC Driver
JDBC 단계
1. 벤더가 제공하는 드라이버를 빌드패스에 추가(pom.xml)
2. 드라이버 로딩
3. Connection 수립
4. Query 객체 생성
Statement : 기본 쿼리 객체로 모든 쿼리 객체의 상위.
PreparedStatement(선컴파일된 쿼리 객체) : 쿼리 객체 생성시 미리 고정된 쿼리문에 의해 컴파일된 쿼리 객체가 생성.
CallableStatement : procedure/function 등 일련의 명령 집합객체를 실행할때.
5. Query 실행
ResultSet executeQuery : SELECT
(rowcount) int executeUpdate : INSERT/UPDATE/DELETE
6. 자원 해제(close)
SELECT * FROM DATABASE_PROPERTIES;
<DataBasePropertyVO>
package kr.or.ddit.vo; import java.io.Serializable; public class DataBasePropertyVO implements Serializable{ // carmel 방식 변환 private String propertyName; private String propertyValue; private String description; @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((description == null) ? 0 : description.hashCode()); result = prime * result + ((propertyName == null) ? 0 : propertyName.hashCode()); result = prime * result + ((propertyValue == null) ? 0 : propertyValue.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; DataBasePropertyVO other = (DataBasePropertyVO) obj; if (description == null) { if (other.description != null) return false; } else if (!description.equals(other.description)) return false; if (propertyName == null) { if (other.propertyName != null) return false; } else if (!propertyName.equals(other.propertyName)) return false; if (propertyValue == null) { if (other.propertyValue != null) return false; } else if (!propertyValue.equals(other.propertyValue)) return false; return true; } public String getPropertyName() { return propertyName; } public void setPropertyName(String propertyName) { this.propertyName = propertyName; } public String getPropertyValue() { return propertyValue; } public void setPropertyValue(String propertyValue) { this.propertyValue = propertyValue; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } @Override public String toString() { return "DataBasePropertyVO [propertyName=" + propertyName + ", propertyValue=" + propertyValue + ", description=" + description + "]"; } }
<11/jdbcDesc.jsp>
<%@page import="java.util.List"%> <%@page import="java.util.ArrayList"%> <%@page import="kr.or.ddit.vo.DataBasePropertyVO"%> <%@page import="java.sql.SQLException"%> <%@page import="java.sql.ResultSet"%> <%@page import="java.sql.Statement"%> <%@page import="java.sql.Connection"%> <%@page import="java.sql.DriverManager"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>11/jdbcDesc.jsp</title> </head> <body> <h4>JavaDataBaseConnectivity - JDBC Driver</h4> <pre> JDBC 단계 1. 벤더가 제공하는 드라이버를 빌드패스에 추가(pom.xml) 2. 드라이버 로딩 3. Connection 수립 4. Query 객체 생성 Statement : 기본 쿼리 객체로 모든 쿼리 객체의 상위. PreparedStatement(선컴파일된 쿼리 객체) : 쿼리 객체 생성시 미리 고정된 쿼리문에 의해 컴파일된 쿼리 객체가 생성. CallableStatement : procedure/function 등 일련의 명령 집합객체를 실행할때. 5. Query 실행 ResultSet executeQuery : SELECT (rowcount) int executeUpdate : INSERT/UPDATE/DELETE 6. 자원 해제(close) <% Class.forName("oracle.jdbc.driver.OracleDriver"); String url = "jdbc:oracle:thin:@localhost:1521:xe"; String user = "LAI"; String password = "java"; // try with resource 구문 List<DataBasePropertyVO> dataList = new ArrayList<>(); try( // Closable 객체 선언 Connection conn = DriverManager.getConnection(url, user, password); Statement stmt = conn.createStatement(); ){ String sql = "SELECT PROPERTY_NAME, PROPERTY_VALUE, DESCRIPTION FROM DATABASE_PROPERTIES"; ResultSet rs = stmt.executeQuery(sql); while(rs.next()){ DataBasePropertyVO vo = new DataBasePropertyVO(); dataList.add(vo); vo.setPropertyName(rs.getString("PROPERTY_NAME")); vo.setPropertyValue(rs.getString("PROPERTY_VALUE")); vo.setDescription(rs.getString("DESCRIPTION")); } }catch(SQLException e){ throw new RuntimeException(e); } %> </pre> <table> <% for(DataBasePropertyVO tmp : dataList){ %> <tr> <td><%=tmp.getPropertyName()%></td> <td><%=tmp.getPropertyValue()%></td> <td><%=tmp.getDescription()%></td> </tr> <% } %> </table> </body> </html>
문제점
-드라이버 로딩은 한번만 하면 되는데 지금 코드로는 해당jsp를 실행할때 마다 저장하려고함
- 계정정보는 변경될 수 있음 그래서 변경될 수 있는 코드가 존재
-모델 1구조이다...
바꿔보자
static : 딱한번 실행되는 코드
refactoring작업
Factory method[Object] pattern: 하나의 객체에 대한 생성을 또 다른 객체가 전담하는 구조
package kr.or.ddit.db; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; /** * Factory method[Object] pattern * : 하나의 객체에 대한 생성을 또 다른 객체가 전담하는 구조 * */ public class ConnectionFactory { static{ try { Class.forName("oracle.jdbc.driver.OracleDriver"); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } public static Connection getConnection() throws SQLException { // 예외 이메소드의 호출자가 가져감 String url = "jdbc:oracle:thin:@localhost:1521:xe"; String user = "LAI"; String password = "java"; Connection conn = DriverManager.getConnection(url, user, password); return conn; } }
<%@page import="kr.or.ddit.db.ConnectionFactory"%> <%@page import="java.util.List"%> <%@page import="java.util.ArrayList"%> <%@page import="kr.or.ddit.vo.DataBasePropertyVO"%> <%@page import="java.sql.SQLException"%> <%@page import="java.sql.ResultSet"%> <%@page import="java.sql.Statement"%> <%@page import="java.sql.Connection"%> <%@page import="java.sql.DriverManager"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>11/jdbcDesc.jsp</title> </head> <body> <h4>JavaDataBaseConnectivity - JDBC Driver</h4> <pre> <% // try with resource 구문 List<DataBasePropertyVO> dataList = new ArrayList<>(); try( // Closable 객체 선언 Connection conn =ConnectionFactory.getConnection(); Statement stmt = conn.createStatement(); ){ String sql = "SELECT PROPERTY_NAME, PROPERTY_VALUE, DESCRIPTION FROM DATABASE_PROPERTIES"; ResultSet rs = stmt.executeQuery(sql); while(rs.next()){ DataBasePropertyVO vo = new DataBasePropertyVO(); dataList.add(vo); vo.setPropertyName(rs.getString("PROPERTY_NAME")); vo.setPropertyValue(rs.getString("PROPERTY_VALUE")); vo.setDescription(rs.getString("DESCRIPTION")); } }catch(SQLException e){ throw new RuntimeException(e); } %> </pre> <table> <% for(DataBasePropertyVO tmp : dataList){ %> <tr> <td><%=tmp.getPropertyName()%></td> <td><%=tmp.getPropertyValue()%></td> <td><%=tmp.getDescription()%></td> </tr> <% } %> </table> </body> </html>
properties파일을 이용한 설정을 외부로 분리
자꾸 바뀌는 코드 자바코드에 있는것은 안좋아 별개의 외부의 설정파일 뺴는것이 좋음
1. 클래스패스
2.클래스패스리소스
bin 실제클래스패스 클래스로더가 관리
languageLap
<sampe.properties>
prop1=value1 prop2=한글값
<message_en.properties>
prop1=value1 prop2=English
<message_ko.properties>
prop1=value1 prop2=한글값
<PropertiesFileRead.java>
package kr.or.ddit.properties; import java.io.IOException; import java.io.InputStream; import java.util.Enumeration; import java.util.Locale; import java.util.Map.Entry; import java.util.Properties; import java.util.ResourceBundle; public class PropertiesFileRead { public static void main(String[] args) { // useProperties(); //sample.properties실행할때 useResourceBundle(); } private static void useResourceBundle() { String baseName ="kr.or.ddit.properties.message"; ResourceBundle bundle =ResourceBundle.getBundle(baseName); Enumeration<String> keys = bundle.getKeys(); while(keys.hasMoreElements()) { String key =(String)keys.nextElement(); String value =bundle.getString(key); System.out.printf("%s:%s \n",key,value); } } private static void useProperties() { String cpPath ="kr/or/ddit/properties/sample.properties"; ClassLoader loader = Thread.currentThread().getContextClassLoader(); try ( InputStream is = loader.getResourceAsStream(cpPath); ){ Properties properties = new Properties(); //property정보를 컬렉션처럼 관리 map과 동일 properties.load(is); //사이즈0이었던것이 받아오게됨 for(Entry<Object, Object> entry :properties.entrySet()) { System.out.printf("%s: %s \n", entry.getKey(), entry.getValue()); } }catch (IOException e) { throw new RuntimeException(e); } } }
dbInfo.properties파일 따로 만들어서 해보기
=>properties파일을 이용한 설정을 외부로 분리
<%@page import="kr.or.ddit.db.ConnectionFactory"%> <%@page import="java.util.List"%> <%@page import="java.util.ArrayList"%> <%@page import="kr.or.ddit.vo.DataBasePropertyVO"%> <%@page import="java.sql.SQLException"%> <%@page import="java.sql.ResultSet"%> <%@page import="java.sql.Statement"%> <%@page import="java.sql.Connection"%> <%@page import="java.sql.DriverManager"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>11/jdbcDesc.jsp</title> </head> <body> <h4>JavaDataBaseConnectivity - JDBC Driver</h4> <pre> JDBC 단계 1. 벤더가 제공하는 드라이버를 빌드패스에 추가(pom.xml) 2. 드라이버 로딩 3. Connection 수립 4. Query 객체 생성 Statement : 기본 쿼리 객체로 모든 쿼리 객체의 상위. PreparedStatement(선컴파일된 쿼리 객체) : 쿼리 객체 생성시 미리 고정된 쿼리문에 의해 컴파일된 쿼리 객체가 생성. CallableStatement : procedure/function 등 일련의 명령 집합객체를 실행할때. 5. Query 실행 ResultSet executeQuery : SELECT (rowcount) int executeUpdate : INSERT/UPDATE/DELETE 6. 자원 해제(close) <% // try with resource 구문 List<DataBasePropertyVO> dataList = new ArrayList<>(); try( // Closable 객체 선언 Connection conn =ConnectionFactory.getConnection(); Statement stmt = conn.createStatement(); ){ String sql = "SELECT PROPERTY_NAME, PROPERTY_VALUE, DESCRIPTION FROM DATABASE_PROPERTIES"; ResultSet rs = stmt.executeQuery(sql); while(rs.next()){ DataBasePropertyVO vo = new DataBasePropertyVO(); dataList.add(vo); vo.setPropertyName(rs.getString("PROPERTY_NAME")); vo.setPropertyValue(rs.getString("PROPERTY_VALUE")); vo.setDescription(rs.getString("DESCRIPTION")); } }catch(SQLException e){ throw new RuntimeException(e); } %> </pre> <table> <% for(DataBasePropertyVO tmp : dataList){ %> <tr> <td><%=tmp.getPropertyName()%></td> <td><%=tmp.getPropertyValue()%></td> <td><%=tmp.getDescription()%></td> </tr> <% } %> </table> </body> </html>
package kr.or.ddit.db; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; /** * Factory method[Object] pattern * : 하나의 객체에 대한 생성을 또다른 객체가 전담하는 구조 * */ public class ConnectionFactory { private static String url; private static String user; private static String password; static { 스태틱 코드블럭. 1번 단계에서 딱 한번 실행됨 String dbInfoPath = "kr/or/ddit/db/dbInfo.properties"; try( InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(dbInfoPath); ) { // Class.forName("oracle.jdbc.driver.OracleDriver"); Properties dbInfo = new Properties(); //map처럼 키와 벨류 처럼 사용됨 dbInfo.load(is); property는 load()라는 메소드를 쓰는것 url = dbInfo.getProperty("url"); user = dbInfo.getProperty("user"); password = dbInfo.getProperty("password"); Class.forName(dbInfo.getProperty("driverClassName")); } catch (Exception e) { throw new RuntimeException(e); } } public static Connection getConnection() throws SQLException { Connection conn = DriverManager.getConnection(url, user, password); return conn; } }
driverClassName=oracle.jdbc.driver.OracleDriver url:jdbc:oracle:thin:@localhost:1521:xe user=LAI password=java
SOLID 원칙 적용 S는 단일 책임의 원칙
모델2구조확장해서 mvc패턴으로 만들자
-부가설명
서블릿 (컨트롤러)
jsp (뷰)
모델이 없다, 모델 레이어를 분리하면 Servlet이자 컨트롤러의 책임이 분리됨.
실행코드캡슐화
1. 데이터 보호
2. 실행코드를 감추기위한 -> 인터페이스 구조를 통해서 구현
인터페이스를 분리함으로써 다형성을 구현할 수 있다.
최종적으로 모델2구조, 레이어는 5개
728x90'웹프로그래밍' 카테고리의 다른 글
회원등록, DB -22.06.23 (0) 2022.06.23 로그인처리, 템플릿맛보기-0622 (0) 2022.06.22 기본객체2, scope-0621 (0) 2022.06.21 ServletContext,File explorer -22.06.20 (0) 2022.06.21 로그인,기본객체 -22.06.16~06.17 (0) 2022.06.17