<예제1>
package com.step6;
import java.util.List;
import java.util.Map;
import javax.swing.JButton;
import java.util.ArrayList;
import java.util.HashMap;
/*
* 업무요청에 대한 결과가 조인이 불가피할 때 하나의 클래스로 제네릭을 사용할 수 없다
* Map 인터페이스를 사용하는 것이 효과적임 - 키와 값으로 관리함
* 키를 컬럼명으로 통일하면 일관성있는 변수명으로 접근이 가능함 - 속도도 빠름
*/
class Emp1{
private int empno = 0;
private String ename = null;
}
class Dept1{
private String dname = null;
}
// 컬렉션 프레임워크란? 자료구조를 API로 구현한 것
// 이것들의 역할은 읽기와 쓰기, 추가로 검색기능지원
public class AddList {
public static void main(String[] args) {
JButton jbtnSelect = new JButton();
// 선언부와 생성부의 이름이 다르면 다형성을 누릴 수 있다.
// 다형성에 대한 전제조건이다.
// 인터페이스, 추상클래스 변수명 = new 구현체클래스();
// 재사용성을 높인다. 이식성을 좋게 함. 유연하다
// 기존의 코드를 변경해야 한다 - 있는 걸 바꾼다 - 사이드이펙트(부수효과) 발생함
// 이식성, 재사용성 - 객체지향 언어가 추구하는 방향성
// 전역변수 - 클래스 중심의 코딩을 전개하기 - 중요함 - 유지됨 - 람다식과 같은 함수형에서는 사용하지 않는다 - 왜냐면 사이드이펙트
// 지역변수 - 처리하면 그 메소드 안에서만 유지됨 - 다른 사이드이펙트 발생하지 않음.
// 안전함 - 람다식이라는 함수형 프로그래밍 지원 가능한 이유
// 상속받거나 구현체 클래스를 선언할 때 하위클래스를 상속받는 게 더 많은 변수와 메소드를 사용할 수 있다
List<JButton> li = new ArrayList<>();
// List 인터페이스의 구현체 클래스가 ArrayList이다.
// 인터페이스는 단독으로 인스턴스화를 할 수 없다.
List<Map<String,Object>>list = new ArrayList<>(); // []형식을 가짐(Gson. lib 데이터 수집, 형전환, 변환) - JSON
Map<String,Object>map = new HashMap<>();
map.put("empno",7782);
map.put("ename","CLARK");
map.put("dname","ACCOUNTING");
list.add(map);
}
}
<예제2-1>
// 다형성 활용하는 방법
package com.step6;
public class Super1 {
int a=1;
void methodA() {
System.out.println("methodA 호출");
}
}
<예제2-2>
package com.step6;
// 다형성
// 같은 메소드를 호출했는데 그 결과가 달라진다
// me.methodB(), sup1.methodB()
public class Me extends Super1 {
public void methodC() {
System.out.println("methodC()호출");
}
public static void main(String[] args) {
Me me = new Me();
Super1 sup1 = new Me(); // 선언부와 생성부의 이름이 다른 것에 대해 얘기하고 있음(다형성)
// 이게 가능하지만, 가능하다고 해서 methodC를 호출할 수 있는 건 아니다. 불가함
Super1 sup11 = new Super1();
System.out.println(me.a);
me.methodA();
sup1.methodA();
// 1. 상위 클래스 타입의 인스턴스 변수로 하위 클래스에 정의된 메소드를 호출불가함
sup1.methodC(); // 에러
sup11.methodC(); // 에러
me.methodC();
}
}
// 1. sup1으로 methodC 호출할 수 있을까? - 없다
// me로 methodC 호출할 수 있을까?
<예제2-3>
package com.step6;
public class Super2 extends Super1 {
int b = 2;
void methodB() {
// 내 안에 선언된 변수가 아니어도 부모가 가진 변수는 호출할 수 있다
System.out.println(a);
System.out.println("methodB() 호출");
}
// super2 클래스를 상속받는 클래스에서는 methodB와 methodC를
public void methodC() {
System.out.println("methodC()호출");
}
}
<예제2-4>
package com.step6;
public class Me2 extends Super2 {
@Override
public void methodC() {
System.out.println("Me2: methodC()호출");
}
public static void main(String[] args) {
Me2 me = new Me2();
Super2 sup1 = new Me2();
Super2 sup11 = new Super2();
System.out.println(me.a);
// Me2타입은 Super2만 상속받았지만, 그 전에 Super1을 상속받고 있으므로 Super1에서 정의된 메소드 호출은 합법이다
me.methodA();
sup1.methodA();
// 상위 클래스 타입의 인스턴스 변수로 하위 클래스에 정의된 메소드를 호출불가함
// 만일 오버라이드 관계에 있어도 불가능한 것일까?
sup1.methodC(); // sup1은 Super2타입인데 생성된 객체는 Me2타입이다. 그래서 헷갈린다
sup11.methodC(); // sup11은 Super2의 정의된 메소드가 호출됨
me.methodC(); // Me2가 출력될 것이다
}
}
JSON(제이슨, JavaScript Object Notation)은 속성-값 쌍(attribute–value pairs), 배열 자료형(array data types) 또는 기타 모든 시리얼화 가능한 값(serializable value) 또는 키-값 쌍으로 이루어진 데이터 오브젝트를 전달하기 위해 인간이 읽을 수 있는 텍스트를 사용하는 개방형 표준 포맷이다.
JSON의 공식 인터넷 미디어 타입은 application/json이며, JSON의 파일 확장자는 .json이다.
<오라클 예제1>
SELECT
컬럼명1, 컬럼명2,...
FROM 집합이름1, 집합이름2,....
WHERE 집합이름1.컬럼명 = 집합이름2.컬럼명
SELECT
e.empno, e.ename, d.dname
FROM emp e, dept d
WHERE e.deptno = d.deptno;
-- 오라클 컬럼은 자바에서 변수이다.
-- 기본키는 not null제약조건이다. unique(유일무이)하다, 식별자 역할함, 인덱스를 제공함 - 검색 속도빠름
-- 메모장에 저장하는 것과는 뭔가 달라야 함
-- dept집합과 1:n관계형태에 있는 emp집합은 dept집합의 deptno를 받아서 태어난 집합임
-- 부서집합의 deptno은 emp집합으로 가서 외래키가 되었다.
SELECT empno FROM emp;
JDBC API 연동하기 - 원시적인 방법 - 생산성이 떨어짐, 코드양이 늘어남(오타)
반복되는 코드의 양이 점점 늘어난다 - 일괄처리가 불가능해진다
학습목표 - List, Map 활용 연습 + CRUD 포함 - 웹개발 게시판 수준을 8시간 이내에 처리 가능한가
ORM 솔루션 - iBatis -> MyBatis -> 전체 코딩량이 30%이상 줄어듦
Spring - JPA API - Hibernate사용함 - sql문이 없다
sql은 없지만 클래스 설계를 해야 한다
업무적인 depth가 깊어지면 조인대상 테이블이 4~5개 이상이다.
무한 루프(반복) - 재귀호출
<예제1-2. JSON>
package com.step6;
import java.util.List;
import java.util.Map;
import javax.swing.JButton;
import com.google.gson.Gson;
import java.util.ArrayList;
import java.util.HashMap;
/*
* 업무요청에 대한 결과가 조인이 불가피할 때 하나의 클래스로 제네릭을 사용할 수 없다
* Map 인터페이스를 사용하는 것이 효과적임 - 키와 값으로 관리함
* 키를 컬럼명으로 통일하면 일관성있는 변수명으로 접근이 가능함 - 속도도 빠름
*/
class Emp1{
private int empno = 0;
private String ename = null;
}
class Dept1{
private String dname = null;
}
// 컬렉션 프레임워크란? 자료구조를 API로 구현한 것
// 이것들의 역할은 읽기와 쓰기, 추가로 검색기능지원
public class AddList {
public static void main(String[] args) {
JButton jbtnSelect = new JButton();
// 선언부와 생성부의 이름이 다르면 다형성을 누릴 수 있다.
// 다형성에 대한 전제조건이다.
// 인터페이스, 추상클래스 변수명 = new 구현체클래스();
// 재사용성을 높인다. 이식성을 좋게 함. 유연하다
// 기존의 코드를 변경해야 한다 - 있는 걸 바꾼다 - 사이드이펙트(부수효과) 발생함
// 이식성, 재사용성 - 객체지향 언어가 추구하는 방향성
// 전역변수 - 클래스 중심의 코딩을 전개하기 - 중요함 - 유지됨 - 람다식과 같은 함수형에서는 사용하지 않는다 - 왜냐면 사이드이펙트
// 지역변수 - 처리하면 그 메소드 안에서만 유지됨 - 다른 사이드이펙트 발생하지 않음.
// 안전함 - 람다식이라는 함수형 프로그래밍 지원 가능한 이유
// 상속받거나 구현체 클래스를 선언할 때 하위클래스를 상속받는 게 더 많은 변수와 메소드를 사용할 수 있다
List<JButton> li = new ArrayList<>();
// List 인터페이스의 구현체 클래스가 ArrayList이다.
// 인터페이스는 단독으로 인스턴스화를 할 수 없다.
// List는 row를 관리한다.
// 제네릭 타입에는 테이블 구조에서 컬럼에 해당하는 값을 관리한다.
// VO 패턴과 Map 타입을 사용할 수 있는데 VO타입에는 타입이 정확해서 형전환이 필요없지만
// Map은 객체 타입으로 받기 때문에 그 값을 가지고 연산을 할 때는 형전환을 해야함(CastingException이 다수 발생가능함)
// 제네릭 타입에는 멀티 타입을 적을 수 없어서 2개 이상의 집합을 조인했을 경우 VO타입보다는 Map을 사용하는 것이
// 복잡도를 줄일 수 있다
List<Map<String,Object>>list = new ArrayList<>(); // []형식을 가짐(Gson. lib 데이터 수집, 형전환, 변환) - JSON
Map<String,Object>map = new HashMap<>();
map.put("empno",7782);
map.put("ename","CLARK");
map.put("dname","ACCOUNTING");
list.add(map);
System.out.println(list);
Gson g = new Gson();
String temp = g.toJson(list);
System.out.println(temp);
}
}
<자바 API를 활용하여 오라클 서버(동기화, 데이터영속성 보장)와 통신하기>
java.sql. : 커넥션 풀을 사용하지 않고...
javax.sql. : 엔터프라이즈 서버(중간에 미들웨어 관리:EJB기술-Spring 경량서비스)가 제공하는 커넥션 풀을 사용할 때 쓰는 패키지
DB 연동하는 4단계
1. 물리적으로 떨어져 있는 서버와 연결통로를 확보하기
(전처리 부분: 각 벤더가 제공하는 드라이버 클래스를 로딩하기) - ojdbc6.jar 배포 - 운영서버에 배포시 첨부해야 함
서버의 ip주소, port, scott, tiger - 상수로 처리해서 캡슐화 해서 사용
java.sql.connection(Interface)
sql문을 자바로 작성하여 오라클 서버에 전달하고 그 처리를 요청함
SELECT문 - executeQuery():ResultSet(Interface-커서를 조작하는 데 필요한 메소드를 정의하고 있음)
INSERT, UPDATE, DELETE - executeUpdate():int - PreparedStatement(Interface) - 전령역할
Connection con = DriverManager.getConnection(URL, "Scott", "tiger");
PreparedStatement pstmt = con.PreparedStatement("sql문");
ResultSet rs = pstmt.executeQuery();
while(rs.next()){
Map or VO 담기 - 한 개 로우만 담을 수 있다
list.add(Map or VO)
}
<예제>
package com.step6;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
/*
* SELECT empno FROM emp;
FROM emp
WHERE empno =:x; -- 파라미터자리
업무에 따라 집합 이름과 컬럼명만 바뀐다. 나머지는 다 그대로이다. - syntax - 문법
1. parsing한다.
2. DBMS에게 실행계획을 받아낸다.
3. 옵티마이저가 실행계획에 따라 처리하기
4. open..커서 갖다대고, 그 위치에 데이터 있으면 메모리 올리는 작업(fetch)-그리고 close
*/
public class Annoymous1 extends JFrame implements ActionListener {
JButton jbtn = new JButton("조회");
public Annoymous1() {
jbtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
System.out.println("조회");
} // end of actionPerformed
});
this.add("North",jbtn);
this.setSize(500, 400);
this.setVisible(true);
}
public static void main(String[] args) {
new Annoymous1();
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
오라클 서버에서 응답으로 오는 정보를 취득하려면 이종간이므로 오라클에서 제공하는 기능들을 추상화 해야 한다
확장성, 유지보수
구현하는 메소드가 존재함(메소드 오버라이딩)
사용한 자원은 반드시 명시적으로 반납하라 - 자바 튜닝팀 요구사항
공통코드 - 반복되는 코드를 줄임
이유는 MyBatis로 처리한다
계속해서 반복되는 코드를 찾아본다 - 개선 의지
1. 드라이버 클래스 반복이다. - insert, update, delete, select
: 저 DML에서 바뀌는 건 DML만 변경되고 컬럼명 변경됨
: 상세조회라면 WHERE empno=7566
클래스 이름: oracle.jdbc.driver.OracleDriver
<예제1-DB연동>
package com.util;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class DBConnectionMgr {
// null로 초기화하는 이유는 null 체크를 해서 null일 때만 새로 인스턴스화 하고
// null 아니면 그냥 계속 사용하자
static DBConnectionMgr dbMgr = null; // 왜 static인가요? - 싱글톤 패턴으로 흉내내보기
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
public static final String _DRIVER = "oracle.jdbc.driver.OracleDriver";
public static final String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl11";
public static final String user = "scott";
public static final String pw = "tiger";
// Calendar 클래스처럼 메소드를 통해서 객체 주입 받기
public static DBConnectionMgr getInstance() { // 공유- 하나이다-복제본을 만들지 않겠습니다
// 메소드를 통해서 객체생성을 하므로 if문 사용해서 조건별 객체생성이 가능해짐
if(dbMgr==null)dbMgr = new DBConnectionMgr();
return dbMgr;
}
// 리턴 타입으로 연결통로를 확보한 con을 얻는다
// Connection(url, 계정 정보 일치 - 인증실패, 에러 코드) -> PrepareStatement(쿼리문 전달, 처리 요청함 ->
// 앞에 객체가 주입되지 않으면 나머지 뒤에는 모두 null인 상태에 놓인다.
public Connection getConnection()
{
// 예외처리시 try..catch블록을 사용하는데 멀티 블록이 가능함 : 단 하위에서 상위클래스로 처리함
try {
// 각 제조사의 드라이버 클래스를 로딩하기 - ojdbc6.jar - 문자열로써 객체 주입 받아낸다 - 인터페이스가 필요함
// 그 인터페이스를 제조사가 제공해야 한다 - 노출시 - 핵심기술 유출
Class.forName("oracle.jdbc.driver.OracleDriver"); // java reflection api 공부 - F/W 만들 수 있다
// 물리적으로 떨어져있는 오라클 서버와 연결통로 확보
// getConnection메소드의 원형도 static 붙어있다 - 하나다
con = DriverManager.getConnection(url,user,pw);
} catch(ClassNotFoundException ce) {
System.out.println("ojdbc6.jar를 설정하지 않았다. 그래서 클래스를 못찾는다.");
} catch (Exception e) {//비번이 틀린경우,
e.printStackTrace();
}
return con;
}
//위 코드에서 22번과 24번 호출시 에러가 없다면 catch블록은 경유하지 않는다.
public static void freeConnection(ResultSet rs, PreparedStatement pstmt, Connection con){
try {
if(rs !=null) rs.close();
if(pstmt !=null) pstmt.close();
if(con !=null) con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void freeConnection(PreparedStatement pstmt, Connection con){
try {
if(pstmt !=null) pstmt.close();
if(con !=null) con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void freeConnection(ResultSet rs, CallableStatement cstmt, Connection con){
try {
if(rs !=null) rs.close();
if(cstmt !=null) cstmt.close();
if(con !=null) con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void freeConnection(CallableStatement cstmt, Connection con){
try {
if(cstmt !=null) cstmt.close();
if(con !=null) con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
<예제1-2>
package com.util;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class DBConnectionMgr {
// null로 초기화하는 이유는 null 체크를 해서 null일 때만 새로 인스턴스화 하고
// null 아니면 그냥 계속 사용하자
static DBConnectionMgr dbMgr = null; // 왜 static인가요? - 싱글톤 패턴으로 흉내내보기
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
public static final String _DRIVER = "oracle.jdbc.driver.OracleDriver";
public static final String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl11";
public static final String user = "scott";
public static final String pw = "tiger";
// Calendar 클래스처럼 메소드를 통해서 객체 주입 받기
public static DBConnectionMgr getInstance() { // 공유- 하나이다-복제본을 만들지 않겠습니다
// 메소드를 통해서 객체생성을 하므로 if문 사용해서 조건별 객체생성이 가능해짐
if(dbMgr==null)dbMgr = new DBConnectionMgr();
return dbMgr;
}
// 리턴 타입으로 연결통로를 확보한 con을 얻는다
// Connection(url, 계정 정보 일치 - 인증실패, 에러 코드) -> PrepareStatement(쿼리문 전달, 처리 요청함 ->
// 앞에 객체가 주입되지 않으면 나머지 뒤에는 모두 null인 상태에 놓인다.
public Connection getConnection()
{
// 예외처리시 try..catch블록을 사용하는데 멀티 블록이 가능함 : 단 하위에서 상위클래스로 처리함
try {
// 각 제조사의 드라이버 클래스를 로딩하기 - ojdbc6.jar - 문자열로써 객체 주입 받아낸다 - 인터페이스가 필요함
// 그 인터페이스를 제조사가 제공해야 한다 - 노출시 - 핵심기술 유출
Class.forName("oracle.jdbc.driver.OracleDriver"); // java reflection api 공부 - F/W 만들 수 있다
// 물리적으로 떨어져있는 오라클 서버와 연결통로 확보 // ClassNotFoundException
// getConnection메소드의 원형도 static 붙어있다 - 하나다. 복제 허용 안함 - 하나로 사용하고 반납하고 또 사용한다
// getConnection메소드 호출 때문에 예외처리를 하였다. - try, catch블록
// 이유는 URL이 존재하지 않을 경우 - 런타임에러(실행에러임) - 논리의 오류(비교연산자) - 사이드이펙트(부작용)
// 사이드 이펙트가 발생하지 않도록 (예방코드) - 신뢰도 - 지역변수 좋다 - 람다식, arrow function
con = DriverManager.getConnection(url,user,pw); // 파라미터가 3개다
} catch(ClassNotFoundException ce) {
System.out.println("ojdbc6.jar를 설정하지 않았다. 그래서 클래스를 못찾는다.");
} catch (Exception e) {//비번이 틀린경우,
e.printStackTrace();
}
return con;
}
//위 코드에서 22번과 24번 호출시 에러가 없다면 catch블록은 경유하지 않는다.
public static void freeConnection(ResultSet rs, PreparedStatement pstmt, Connection con){
try {
if(rs !=null) rs.close();
if(pstmt !=null) pstmt.close();
if(con !=null) con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void freeConnection(PreparedStatement pstmt, Connection con){
try {
if(pstmt !=null) pstmt.close();
if(con !=null) con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void freeConnection(ResultSet rs, CallableStatement cstmt, Connection con){
try {
if(rs !=null) rs.close();
if(cstmt !=null) cstmt.close();
if(con !=null) con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void freeConnection(CallableStatement cstmt, Connection con){
try {
if(cstmt !=null) cstmt.close();
if(con !=null) con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
<예제1-3>
// DB 단위테스트
package com.step5;
public class DBTest {
public static void main(String[] args) {
DeptManager3 dm = new DeptManager3();
dm.getDTOList();
}
}
<SQL문>
SELECT empno, ename
FROM emp
WHERE empno =:x;
create table member1(
m_id varchar2(10) constraints member1_pk primary key,
m_pw varchar2(10) not null,
m_name varchar2(30)
);
insert into member1 values('kiwi','123','키위');
commit;
SELECT
m_name
FROM member1
WHERE m_id =:id
AND m_pw =:pw;
PrepareStatement pstmt = con.prepareStatement("select문");
--? 자리를 치환할 수 있다