자바프로그래밍 언어: JDBC<2>
5. JDBC를 이용한 데이터베이스 연결방법
ResultSet 객체를 생성한다.
ResultSet은 SQL문에 대한 결과를 처리할 수 있는 객체이다.
Statement 인터페이스의 executeQuery() 메서드를 실행한 결과로 ResultSet 객체를 리턴 받는다.
모든 데이터를 한번에 가져올 수 없기 때문에 cursor의 개념을 가지고 있다.
cursor란 ResultSet 객체가 가져올 수 있는 행을 지정해 준다.
처음 커서의 위치는 결과물(필드)에 위치하지 않기 때문에 cusror를 이동해야 한다.
커서를 이동하는 메서드가 ResultSet 의 next() 메서드이다.
next() 메서드의 리턴 타입은 boolean 인데 이는 다음 행의 결과물(필드)이 있으면 true, 없으면 false를 리턴 한다.
ResultSet 객체가 결과물(필드)을 가져올 수 있는 행으로 이동이 되었다면 이제는 실제 결과물(필드)을 가져와야 한다.
ResultSet 인터페이스에는 결과물(필드)을 가져오는 수많은 메서드(getXXX())를 제공한다.
getXXX() 메서드는 oracle의 자료형 타입에 따라 달라지게 된다.
예를 들어 id 컬럼이 varchar2 타입이라면 getString(~) 메서드를 사용해야 하고, age 컬럼이 number 타입이라면 getInt(~) 메서드를 사용해야 한다.
getXXX() 메서드는 두개씩 오버로드 되어 정의 되어 있는데 하나는 정수를 인자로 받는 것과 String 타입으로 인자를 받는 메서드를 제공하고 있다. 커서를 이동하는 메서드가 ResultSet 의 next() 메서드이다.
첫번째 정수를 받는 타입은 select 문 다음에 쓰는 컬럼명의 인덱스를 지정하는데 인덱스의 처음번호는 1부터 시작하게 된다.
두번째 String 타입은 select 문의 다음에 오는 컬럼명으로 지정해야 한다.
모든 객체를 닫는다.
Connection, Statement, ResultSet 객체는 사용이 끝난 후에는 종료를 해 줘야 한다. 종료 해주는 메서드는 모든 객체에 close() 메서드로 정의 되어 있다.
6. Statement 상속관계
Statement 상속관계
Statement 인터페이스는 SQL문을 전송할 수 있는 객체이다.
상속관계를 보면 아래와 같다.
서브 인터페이스로 갈 수록 향상된 기능을 제공한다.
PreparedStatement 기능
PreparedStement는 SQL문의 구조는 동일하나 조건이 다른 문장을 변수 처리함으로써 항상 SQL문을 동일하게 처리할 수 있는 인터페이스 이다.
PreparedStement로 SQL문을 처리하게 되면 LIBRARY CACHE에 저장된 세 가지 작업을 재사용 함으로써 수행 속도를 좀 더 향상시킬 수 있다.
이해를 돕기 위해 SQL문을 전송했을 경우 오라클은 내부적으로 어떻게 작동하는 보도록 하자.
SQL문 전송하게 되면 오라클은 내부적으로 PARSING => EXECUTE PLAN => FETCH 작업을 한다.
이런 3가지 작업을 한 후에 검색한 결과를 SGA 영역 안에 Data Buffer Cache영역에 Block 단위로 저장하게 된다.
SQL문과 PARSING한 결과와 실행계획을 SHARED POOL안에 LIBRARY CACHE에 저장하게 된다.
똑 같은 SQL문을 전송하면 LIBRARY CACHE에 저장된 SQL문과 PARSING한 결과와 실행계획을 그대로 사용하게 된다.
똑 같은 SQL문이라도 대소문자가 하나라도 틀리거나 SQL문이 다르다면 LIBRARY CACHE에 저장된 3가지 작업을 재 사용할 수 없고 다시 PARSING => EXECUTE PLAN => FETCH 작업을 수행하게 된다.
PreparedStatement 사용방법
PreparedStatement의 객체 생성은 아래와 같다.
String sql = “select age from test1 where id=?”;
PreparedStatement pstmt = con.prepareStatement(sql);
pstmt.setString(1,”syh1011”);
ResultSet rs = pstmt.executeUpdate();
PreparedStatement는 SQL문을 작성할 때 컬럼 값을 실제로 지정하지 않고, 변수 처리 함으로서 DBMS을 효율적으로 사용한다.
PreparedStatement의 SQL문은 SQL문의 구조는 같은데 조건이 수시로 변할 때 조건의 변수처리를 “?” 하는데 이를 바인딩 변수라 한다.
바인딩 변수는 반드시 컬럼 명이 아닌 컬럼 값이 와야 한다는 것이다.
바인딩 변수의 순서는 “?” 의 개수에 의해 결정이 되는데 시작 번호는 1 부터 시작하게 된다.
바인딩 변수에 값을 저장하는 메서드는 오라클의 컬럼 타입에 따라 지정해 주면 된다. 전에 ResultSet의 getXXX() 메서드와 유사하게 PreparedStatement 인터페이스에는 바인딩 변수에 값을 저장하는 setXXX() 메서드를 제공하고 있다.
CallableStatement 기능
CallableStatement는 DBMS의 저장 프로시저(Stored Procedure)를 호출할 수 있는 인터페이스이다.
저장 프로시저란 파라미터를 받을 수 있고, 다른 애플리케이션이나 PL/SQL 루틴에서 호출할 수 있는 이름을 가진 PL/SQL 블록이다. 즉, SQL문을 프로그램화 시켜 함수화 시킨 스크립트 언어이다.
SQL문을 프로그램화 시켰기 때문에 조건문, 반복문, 변수처리 등을 사용하기 때문에 일괄처리 및 조건에 따라 틀려지는 SQL문을 작성할 때는 유리하다.
이런 Stored Procedure 호출을 가능 하게해 줄 수 있는 인터페이스가 CallableStatement 이다.
CallableStatement 사용 방법
CallableStatement cstmt = con.prepareCall("{call adjust(?,?)}");
CallableStatement는 Connection 인터페이스의 prepareCall(~)를 사용하면 된다.
prepareCall(String procedure) 의 프로시저는 2가지 형태를 가지고 있다.
1. {?= call <procedure-name>[<arg1>,<arg2>, ...]}
2. {call <procedure-name>[<arg1>,<arg2>, ...]}
1번은 <arg1>,<arg2>,..은 PreparedStatement 처럼 바인딩 변수로 처리 하면 되고, ?은 registerOutParameter(~)계열의 메서드를 사용하면 된다.
2번은 <arg1>,<arg2>,..은 PreparedStatement 처럼 바인딩 변수로 처리 한다.
7. JDBC를 이용한 Transaction
트랜잭션(Transcation)
트랜잭션이란 여러 개의 오퍼레이션을 하나의 작업 단위로 묶어 주는 것을 말한다.
트랜잭션은 하나의 작업 단위의 일들은 전체 작업이 모두 올바르게 수행되거나 또는 전체 작업이 모두 수행되지 않아야 한다.
트랜잭션은 네 가지 특성(ACID 특성)을 가지고 있다.
Connection 인터페이스에서 Transaction과 관련된 메서드를 정리하면 다음과 같다.
setAutoCommit(boolean autoCommit) – autoCommit이 true이면 트랜잭션을 시작하지 않겠다는 의미, false 이면 트랜잭션을 시작하겠다는 의미 이다.
commit() – setAutoCommit(false)와 commit() 사이에 있는 모든 operation를 수행하겠다는 의미이다.
rollback() - setAutoCommit(false)와 rollback() 사이에 있는 모든 operation를 수행하지 않겠다는 의미이다.
8. Properties 를 이용한 JDBC 연결과 ResultSetMetaData
Properties
Properites 클래스는 properties파일의 집합을 추상화 클래스이다.
이 클래스는 Stream를 로드하여 저장할 수 있고, 이를 다시 Map 형태로 관리하여 Key를 알면 Key에 대한 Value을 얻어올 수 있는 클래스이다.
C:\jdbc.properties 파일을 아래와 같이 만들어보자.
driver = oracle.jdbc.driver.OracleDriver
url = jdbc:oracle:thin:@localhost:1521:orcl
sser = scott
password = tiger
jdbc.properties 파일을 읽기 위해서는 스트림을 생성해야 한다.
스트림을 Properties 클래스에 로드 시키고, Properties클래스의 getProperty(String key) 메서드를 이용해서 각각의 값을 얻어 올 수 있다.
try{
FileInputStream fis = new FileInputStream("c:\\jdbc.properties");
Properties pro = new Properties();
pro.load(fis);
String driver = pro.getProperty(“driver");
String url = pro.getProperty(“url");
String user = pro.getProperty(“user");
String password = pro.getProperty(“password");
}catch(IOException ee){
ee.printStackTrace();
}
Properties 클래스를 이용하여 JDBC를 연결하게 되면 데이터 베이스가 바뀌는 경우, 또는 데이터 베이스의 IP가 바뀌는 경우 , 사용자가 바뀌는 경우에 jdbc.properties 파일만 수정하여 재 컴파일 방지하고, 유지보수에 용이하게 함이다.
ResultSetMetaData
MetaData란 데이터의 구성요소를 의미한다.
Table명은 알고 있지만 Table를 구성하는 컬럼명 이라든지 , 컬럼명의 자료형등을 알기 위해서는 ResultSetMeta-Data를 이용해야 한다.
ResultSetMetaData는 ResultSet의 구성요소이다. 다시 말해서, SQL의 Table을 구성하는 모든 요소를 알아낼 수 있는 메서드를 제공하고 있다.
ResultSetMetaData 객체를 생성하는 방법은 아래와 같다.
rs = pstmt.executeQuery() ;
ResultSetMetaData rsmd = rs.getMetaData() ;
9. JDBC 2.0
BatchQuery
여러 개의 SQL문을 한꺼번에 전송하는 일괄 처리 방식이다.
JDBC1.0에서는 executeUpdate() 메서드만을 제공하기 때문에 하나의 SQL문만 처리 가능했다.
JDBC2.0에서는 executeBatch() 메서드를 제공해서 SQL문을 일괄 처리할 수 있다.
모든 SQL문을 처리하지 못한다. 즉 INSERT, UPDATE, DELETE, CREATE , DROP , ALTER문 등에서만 사용할 수 있다.
Scrollable
JDBC2.0의 가장 큰 변화 중에 하나는 ResultSet의 커서가 양방향으로 움직(Scrollable)인다는 것이다.
ResultSet의 메서드중에 커서를 내리기위한 메서드로 next() 메서드가 있었다.
이것은 커서를 forward 방향으로 움직이는 것인데, JDBC2.0 에서는 backward 방향으로 움직이는 메서드를 제공하고 있다.
양방향 커서를 코딩하기 위해서는 createStatement()의 두개의 매개변수 갖는 메서드를 제공하고 있다.
JDBC2.0 에서는 createStatement(int resultSetType, int resultSetConcurrency) 메서드를 제공하고 있다.
매개변수 인자로 들어가는 2가지 int 값에 대해 알아보자.
2가지 인자 값은 ResultSet 의 상수 값으로 존재한다.
- resultSetType => TYPE_XXX 형태
• TYPE_FORWARD_ONLY : 커서의 이동이 단 방향만 가능하다. 속도가 빠르다..
• TYPE_SCROLL_INSENSITIVE : 커서의 이동이 양방향 가능하며,
갱신된 데이터를 반영하지 않는다.
• TYPE_SCROLL_SENSITIVE : 커서의 이동이 양방향 가능하며, 갱신된 데이터를 반영한다.
- resultSetConcurrency => CONCUR_XXX 형태
CONCUR_READ_ONLY : 읽기만 된다.
CONCUR_UPDATABLE : 데이터를 동적으로 갱신할 수 있다.
양방향 가능한 Statement 객체를 생성하는 방법은 아래와 같다
Statement stmt = con.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
SavePoint
SAVEPOINT는 트랜잭션 내에 세이브 포인트를 만들 수 있게 해준다.
하나의 트랜잭션에 내에 여러 개의 세이브 포인트를 지정할 수 있다.
트랜잭션 내에 설정 세이브 포인트를 이용하면 세이브 포인트 이전의 작업은 그대로 두고, 세이브 포인트 이후의 작업만 선택적으로 롤백 할 수 있다.
10. JDBC3.0
JDBC3.0
JDBC RowSet 객체는 ResultSet 객체보다 사용법이 편하고, 더 유연한 방법을 제공한다.
썬 마이크로 시스템에서는 RowSet에서 사용 빈도가 높은 5개의 인터페이스를 정의했고, JCP와 DB 벤더에서는 5개의 인터페이스를 구현하였다.
5개의 인터페이스는 JDK 5.0의 한 부분으로 추가 되었다.
5개의 인터페이스에 대한 각각의 구현 클래스는 아래와 같다.
JdbcRowSet
JdbcRowSet은 기본적으로 ResultSet 객체의 기능을 향상 시켰다.
첫 번째 url,user,password, sql문을 설정할 수 있는 메서드를 제공한다. 즉, Connection, Statement, ResultSet 객체를 생성하지 않고, JdbcRowSet 객체로 바로 DBMS를 접근할 수 있다는 뜻이다.
JdbcRowSetImpl jdbcRs = new JdbcRowSetImpl();
jdbcRs.setUrl(“jdbc:oracle:thin:@localhost:1521:orcl”);
jdbcRs.setUsername(“scott”);
jdbcRs.setPassword(“tiger”);
jdbcRs.setCommand(“select * from coffees”);
jdbcRs.execute();
두 번째는 JdbcRowSet은 기본적으로 ResultSet scrollable, update, delete, insert 기능을 가지고 있다.
CacheRowSet
CachedRowSet의 기능은 JdbcRowsSet의 기능을 모두 가지고 있고, 추가적으로 연결이 끊긴 RowSet 객체를 사용 할 수 있는 기능을 가지고 있다.
JDBC 코딩에서는 Connection 객체를 close 하게 되면 ResultSet 객체를 역시 사용할 수 없게 되지만, CachedRowSet 객체는 Connection 객체가 close 하더라도 CachedRowSet 객체는 기존의 ResultSet 객체를 캐쉬하고 있게 된다.
Connection Pool
우리는 앞서 3tier에 대한 대략적인 구조를 살펴봤다.
3tier구조에서 MIDDLEWARE 와 DBMS의 거리가 멀어진다면 JDBC API중에 Connection 객체를 만드는 비용은 상당할 것이다.
왜냐하면 MIDDLEWARE와 DBMS의 실제적인 접속시도는 Connection 객체를 생성할 때 이루어 지기 때문이다.
JDBC API의 가장 코스트가 비싼 자원인 Connection 객체를 미리 생성하여 재 사용하는 메커니즘을 Connection Pool이라고 한다.
Connection Pool 만들기
Connection를 저장할 수 있는 두개의 Vector를 생성한다.
Freed(Vector)는 ConnectionPool 클래스의 객체가 생성될 때 미리 생성된 Connection 객체를 저장하는 장소이다.
Used(Vector)는 실제 미들웨어에서 DBMS와 연결을 할 때 사용하는 Connection 공간이다.
이때 Freed(Vector)에서 Connection 객체를 꺼내와 Used(Vector)에 저장하고 Used(Vector)에 있는 Connection 객체를 실제 애플리케이션에 사용하는 것이다.
'처음배우는 IT' 카테고리의 다른 글
자바프로그래밍 언어: JDBC<1> (0) | 2021.01.26 |
---|---|
자바프로그래밍 언어: 네트워크<2> (0) | 2021.01.25 |
자바프로그래밍 언어: 네트워크<1> (0) | 2021.01.24 |
자바프로그래밍 언어: 입출력 스트림 (0) | 2021.01.21 |
자바프로그래밍 언어: Thread (0) | 2021.01.20 |