StatementEX 안에 반복적으로 나오던 Try~With 구문 안 부분이 SQLAgent로 빠짐(Template Method Pattern)

SQLAgent는 추상클래스이기 때문에 상속되거나 익명클래스로만 만들어질 수 있음.

SQLAgent는 MyConnectionPool에서 MyConnection을 한 개 받아 Connection 인스턴스변수에 넣어줌(MakeConnection() 메소드).

Query를 DB에 던져 data를 읽는 부분은 doJob()에서 구현. closeAll()이 close()역할을 해줌.

Apache DBCP도 이런 식(pooling data sourse example, 897457).


SQLAgent는 timeDAOImpl에서 익명 클래스로 구현됨(StatementEX는 Connection 생성 및 실행이 반복될 때 얼마나 오래 걸리는가를 보여주는 용도). timeDAOImpl이 override하는 getTime() 메소드는 String type을 반환.

TimeDAOImpl의 StringBuilder가 final로 구현됨을 유의깊게 봐야 함.



import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;


public abstract class SQLAgent {

static {

MyConnectionPool.getInstance();

}

protected Connection con;

protected PreparedStatement pstmt;

protected ResultSet rs;

private void makeConnection() throws Exception{

this.con = MyConnectionPool.getInstance().getConnection();

}

public final void doExecute() throws Exception{

try {

makeConnection();

doJob();

} catch (Exception e) {

throw e;

} finally{

closeAll();

}

}

protected abstract void doJob() throws Exception;

private void closeAll() throws Exception{

if(rs !=null){try {rs.close();} catch(Exception e){}}

if(pstmt !=null){try {pstmt.close();} catch(Exception e){}}

if(con !=null){try {con.close();} catch(Exception e){}}

}

}



---------------------------------------------------------------------------------------

SQLAgent의 구현으로 다소 바뀐 StatementEx


public class StatementEx {

public static void main(String[] args) throws Exception {

MyConnectionPool.getInstance();

long start = System.currentTimeMillis();

for (int i = 0; i < 100; i++) {

new SQLAgent() {

@Override

protected void doJob() throws Exception {

pstmt=con.prepareStatement("select sysdate from dual");

rs=pstmt.executeQuery();

rs.next();

System.out.println(rs.getString(1));

}

}.doExecute();

}

long end = System.currentTimeMillis();

System.out.println(end-start);

}

}




-----------------------------------------------------------------------------------------

DAO 맛보기




public interface timeDAO {

public String getTime() throws Exception;

}




public class TimeDAOImpl implements timeDAO {
private static final String query = "select sysdate from dual";
@Override
public String getTime() throws Exception {

final StringBuilder builder = new StringBuilder();
//값 자체 고정이 아니라 내용물이 고정
new SQLAgent() {
@Override
protected void doJob() throws Exception {
pstmt =  con.prepareStatement(query);
//파라미터로 전달 안 받았지만 쓸수있음
rs = pstmt.executeQuery();
rs.next();
builder.append(rs.getString(1));
//익명클래스 최대 장점. 리턴타입 마음대로
}
}.doExecute();
return builder.toString();
}
}


Posted by 타다키치
,


Singleton : private static 변수로 자기 자신의 인스턴스를 가짐. 생성자가 private, 객체를 만들 수 없다. getInstance() 메소드로 객체를 가져옴.

MyConnection은 진짜 Connection을 가지고 있음.

MyConnection을 따로 만드는 이유? Try~With 문에서 AutoClosable될 때 껍데기만 close되도록 하기 위해. 

MyConnectionPool이 MyConnection 객체의 Vector을 가지고 있음(그래서 pool)

MyConnectionPool이 StatementEx에게 MyConnection을 하나 반환한 후에 close 될 때 그 MyConnection이 Vector에 맨 뒤로 다시 추가됨(close()메소드가 MyConnectionPool의 returnConnection()을 실행). MyConnection이 Vector을 통해 계속 순환되는 구조.





import java.sql.Connection;

import java.sql.DriverManager;

import java.util.List;

import java.util.Vector;


public class MyConnectionPool {


List<Connection> conList;

private int idx = 0; 

private static MyConnectionPool instance = new MyConnectionPool();

public static MyConnectionPool getInstance(){

return instance;

}

private MyConnectionPool(){

try{

conList = new Vector<Connection>();

Class.forName("oracle.jdbc.OracleDriver");

String urlPath = "jdbc:oracle:thin:@61.72.16.181:5024:orcl";

String userName = "leepanho";

String pw = "leepanho";

for(int i = 0; i < 10; i++){

conList.add(

new MyConnection(

DriverManager.getConnection(urlPath,userName,pw),

this));

}

}catch(Exception e){

e.printStackTrace();

}

}

public Connection getConnection()throws Exception{

return conList.remove(0);

}

public void returnConnection(Connection con)throws Exception{

conList.add(con);

}

}



----------------------------------------------------------------------------------------

MyConnection = Connection을 implement 해서 클래스를 만듦. 다음의 내용만 추가.


private Connection realCon;

private MyConnectionPool pool;

public MyConnection(Connection con, MyConnectionPool pool){

this.realCon = con;

this.pool = pool;

}

prepareStatement(String sql)와 close() 메소드에는 각각 다음 내용을 추가해 Override.

prepareStatement(String sql):

return realCon.prepareStatement(sql);


close():

try {

        pool.returnConnection(this);

     } catch (Exception e) {

        e.printStackTrace();

     }




------------------------------------------------------------------------------------------


import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.ResultSet;


public class StatementEx {


public static void main(String[] args) throws Exception {

for (int i = 0; i < 100; i++) {

try (Connection con = MyConnectionPool.getInstance().getConnection();

PreparedStatement stmt = con.prepareStatement("select sysdate from dual");

ResultSet rs = stmt.executeQuery();

){

System.out.println(rs);

rs.next(); //

System.out.println(rs.getString(1));

rs.close();

stmt.close();


} catch (Exception e) {

e.printStackTrace();

}

}

}

}


Posted by 타다키치
,

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.