가희의자기개발블로그

Connection Pool 본문

백엔드/JSP

Connection Pool

가희gahui 2020. 6. 12. 12:34
반응형

지금까지 JAVA와 DB를 연동하는 방법으로 DB를 연동할때마다, DAO를 통해 DB에 연결하는 방법을 이용해 왔다. 이 방법의 단점은 웹환경일때, DB와의 연결이 너무 빈번하게 발생하고, 그때마다 커넥션을 생성하고 닫으면 리소스의 낭비와 시간을 많이 소비한다는 것이다.

 

Connection Pool을 본격적으로 알아보기 전에 우선 이전에 사용하던 방식을 먼저 설명하고 그것이 Connection Pool로 어떻게 바뀔 수 있는지 알아보자.

 

1_ JDBC연결 기본 방법

1_1 기본설정

eclipse와 DB와의 연결을 위해서는 JDBC.JAR파일이 필요하다. 아래 포스팅을 참고해 이클립스에 jdbc를 연동한다.

 

https://blog.naver.com/ststage/221256211715

 

자바와 오라클 연동(eclipse, ojdbc6)

자바와 오라클을 연동하려면 jdbc파일이 필요하다. jdbc는 JVM과 DB를 연결시켜주는 아이다. 우선, jd...

blog.naver.com

1_2 Driverloading

자바와 DB를 연동해주기 위해서는 드라이버를 로딩해주어야 한다. 바로 OracleDriver라는 클래스가 필요한데 이 클래스는 jdbc 에서 제공해주는 라이브러리이다. 이 클래스를 생성 해줘야 하는데 사실 이 OracleDriver는 클래스인지 인터페이스인지 알 수가 없다. 

 

클래스라면 그냥 new해서 생성해 주면 되지만, 만약 Interface라면 new로 생성해 줄 수 없기 때문이다. 

그래서 자바에서 제공하는 Class 클래스의 Class.forName() 메소드를 이용하면 된다. 

 

 

  • MySQL의 JDBC Driver Class를 로딩합니다.
  • Class.forName(“driver”)을 이용해서 Driver Class를 로딩하면 객체가 생성되고, DriverManager에 등록됩니다.
  • ex) Class.forName(“com.mysql.jdbc.Driver”)
  • Driver 클래스를 찾지 못할 경우, ClassNotFoundException 예외가 발생 합니다.

 

 

 

1_3 Connection - URL, USER, PASSWORD

지금까지는 자바와 OracleDB 연결을 위한 설정을 마친것이다. 하지만 우리가 원하는 계정의 테이블과는 아직 연동 되지 않았다. 내가 연결하고자 하는 계정과 연결을 해줘야한다. 이를 위해서는 Connection인터페이스를 이용해 줘야한다.

인터페이스를 사용하는 방법은 총 네가지가 있다. 

 

첫째,  implemnets해준다. 

둘째, 익명객체로 선언한다. 

셋째, WindowAdapter클래스처럼 이 인터페이스를 대신 구현해 놓은 클래스를 찾는다.

넷째, 해당 객체를 리턴해주는 클래스의 메소드를 찾는다.

 

우선 첫번째와 두번째 방법을 이용할 경우, 위 인터페이스가 가진 모든 추상메소드를 오버라이드 해줘야 한다. 하지만 우리가 이용하고자하는 Connection 인터페이스의 메소드는 단 한개인데 이 인터페이스는 엄청나게 많은 추상메소드를 가지고 있기 때문에, 이걸 이용해 줄 경우 이 모든 메소드를 오버라이드 해줘야 하기 때문에, 코드도 길어지고 효율이 떨어진다. 

 

그렇다면 세번째 방법은?? Oracle API를 보면, 이 해당 인터페이스를 대신 구현해 좋은 클래스가 없다. (만약 있다면, all known implementing 에 해당 인터페이스를 implements한 클래스가 나오겠지만 아무것도 없다. )

 

마지막 방법을 써야 한다. java.sql에 있는 DriverManager클래스에 Connection 객체를 return 해주는 메소드가 있다. 바로, getConnection함수인데 static함수 이기 때문에 new해줄 필요 없이 DriverManager.getConenction()해주면 된다. 

 

파라미터 인자로 String url, String user, String password가 있다.

url은”jdbc:oracle:thin:@localhost:1521:xe” 이런식으로 써준다… 하나하나 해석해보면 thin은 드라이버 이름으로 오라클이 제공하는 그래픽중 하나이다. 이후 ip주소를 적어주면 된다. 내 컴퓨터의 ip를 이용하기때문에 localhost로 해주었고 다음 숫자 1521은 포트 번호이다.  xe는 설명해주셨는데… 기억이 나지 않는다… 추후 추가하도록… 하겠다.

user은 oracleDB에서 생성한 DB id값을 넣고 비밀번호또한 동일하다. 여기까지해야 DB에 접속이 성공한 것이다.

 

 

1_4 Statement - SQL(insert, delete, update, select...)

이제 자바와 DB의 연결이 끝이 났고 원하는 테이블의 데이터를 SQL문을 이용해서 가지고 오면 된다. 하지만, 자바 파일에 SQL문을 무턱대고 쓰면 될까? 당연히 안된다! 그럼 자바가 SQL문을 인식하게 해줘야 하는데 그럴땐 바로preparedStatement 인터페이스를 이용하면된다. 

 

인터페이스를 이용하려면.. 오버라이드! API를 보면, 오버라이드해줘야하는 추상메소드가 너무나 많다. 그렇다면 Connection 클래스에 preparedStatemnet를 리턴해주는 메소드 prepareStatement()를 이용하면 된다. 

이 prepareStatement는 하나의 sql문을 담당하고 자동으로 Commit해주기 때문에 CRUD를 이용해도 commit해줄 필요가 없다. 

위에서 Connection 인터페이스를 위에서 선언해줬기 때문에 conn.prepareStatement(String sql)메소드를 사용하면 된다.

 

SQL문 작성시 유의사항이 있다.

바로, sql문에 바로 입력하면 보안의 문제가 있다는것이다.

ex) “insert into dbtest values(”+name+”)”; 이렇게 sql문에 직접 입력할 경우  누군가 역컴파일을 했을 경우 해당 column에 뭐가 들어가 있는지 알게 되기 때문에 보안의 문제가 생긴다. 그렇기 때문에 “insert into dbtest values(?)”; 이런식으로 작성해줘야 한다. 

 

sql문작성이 완료되면 이 sql문을 실행해 줘야 한다.  CRUD의 경우 excuteUpdate()메소드가 SELECT의 경우 excuteQuery()가 담당한다. excuteUpdate를 이용할 경우 int를 return하는데 이것은, DB에서 update나 insert시 "1개의 열이 추가되었습니다."라는 메시지가 뜨는데,  여기에 1에 해당하는 것을 반환하는것이다.

excuteQuery()를 이용할 경우 결과값을 받아와야 한다. 이 메서드는 resultSet이라는 개체로 반환을 한다. 

 

이후에 가장중요한 것은 사용했던 Connection, Preparedstatement, ResultSet 객체를 모두 close해줘야 한다.

 

이유는 다음 블로그에서 참조..

 

https://deviant86.tistory.com/502

 

[Java] DB 사용 시에는 꼭 close() 메소드를.

DB Connection과 Connection Pool, DataSource Connection 객체를 얻을 때 DB와 WAS 사이에는 통신을 해야하기 때문에 대기 시간이 소요된다. Connection 객체를 생성하는 부분에서 발생하는 대기 시간을 줄이고,..

deviant86.tistory.com

 

 

 

02_ Connection Pool

: 웹 환경에서 DB 와의 연결이 빈번하게 발생하는 경우, 그 때마다 커넥션을 생성하고 닫게되면 리소스의 낭비와 연결시 시간을 많이 소비한다.

 

ex) 네이버만 해도 대한민국에 수천만명이 사용할텐데 그 사람들이 네이버에 접속할 때마다 커넥션을 생성하고 닫게되면 상상만해도 끔찍함.

 

- 이를 개선하기 위해 미리 커넥션을 생성해서 Pool 에 넣어 놓고 요청이 있으면 커넥션을 Pool 에서 가져다 쓰고, 다 쓰면 다시 Pool 에 반납한다.

이와 같은 기법을 Connection Pool 이라고 한다.

 

: 서버에 미리 Connection 를 설정해 놓는 것

 

: 데이터베이스와 연결된 커넥션을 미리 만들어서 풀(Pool)속에 저장해 두고 있다가 필요할 때 커넥션을 풀에서 가져다 쓰고 다시 풀에 반환(close)하는 기법

 

: Connection의 내용이 바뀌면 서버만 수정해주면 된다

 

: 풀속에 미리 커넥션이 생성 되어있기 때문에 커넥션을 생성하는데 드는 연결시간이 소비되지 않는다

: 커넥션을 계속해서 재사용하기 때문에 생성되는 커넥션 수는 많지 않다

: 오라클 주소, 드라이버, ID, PW를 서버에 숨겨 놓음으로 보안에 좋다

 

2_1) DataSource

DataSource객체는 Connection Pool을 관리하는 객체이다. 이 객체는 JNDI서버를 통해서 이용된다.

Connection을 얻어오기 위해서는 javax.sql.DataSource를 이용해 줘야한다.

 

1)JNDI Server에서 lookup()메서드를 호출해 DataSource 객체를 얻는다.

2) DataSource의 getConnection()메서드를 호출해 Connection 객체를 얻는다. 

3) Connection을 가지고 DB질의를 수행합니다.

4) 질의가 끝나며 Connection 객체를 close()해준다.

 

2_2) JNDI

Java Naming & Directory Interface 서비스는 "이름"을 가지고 "객체"를 얻을 수 있는 서비스이다. DNS가 도메인으로부터 IP를 획득하는 서비스를 제공하는 것처럼 "이름"에 맺어진 "객제"를 반환하는 역할을 한다.

이 JNDI는 context.xml 파일에 <Resource>라는 태그로 등록 할 수 있다. 

 

server.xml에서 <Context></Context>에 추가해야하는데 따로 context.xml를 만들어서 사용해보자

: META-INF 에 context.xml파일 생성후 아래 코드를 입력해준다. 

<Context docBase="memberJSP"

                path="/memberJSP" 
                reloadable="true" 
                source= "org.eclipse.jst.jee.server:memberJSP">

      <Resource name="jdbc/oracle"

               type="javax.sql.DataSource"

            driverClassName=" oracle.jdbc.driver.OracleDriver"

            url="jdbc:oracle:thin:@localhost:1521:xe"

            username="c##java" 
            password="bit" 
            maxActive="20" 
            maxIdle="3" 
            removeAbanded="true" 
            />

</Context>

1) driverClassName : JDBC Driver의 경로를 입력합니다.

2) url : 접속할 DB 서버의 url을 입력합니다.

3) username : DB에 로그인할 계정 ID

4) password : DB에 로그인할 패스워드

5) name : JNDI에 등록될 자원의 "이름"

6) type : JNDI에서 "이름"을 찾았을 때, 연결될 "객체" --> DataSource를 통해 Connection을 제어하기 때문에 이를 지정합니다.

7) maxTotal: 생성할 Connection의 개수를 지정

8) maxWaitMillis : 커넥션이 없을 때 쓰레드가 기다리는 시간(ms). 이 시간이 끝나면 Exception이 발생합니다.

9) maxActive - 커넥션 풀이 제공할 최대 커넥션 개수

10) maxIdle - 사용되지 않고 풀에 저장될 수 있는 최대 커넥션의 개수, 음수일 경우 제한을 두지 않음

11) maxWait - 커넥션 풀을 대기하는 대기시간, 음수일 경우 제한을 두지 않음

 

※Tomcat 5.0 부터는 web.xml파일에 resource파일을 적을 필요가 없다.

 

2_3 Connection Pool 사용해보기

2_3_1)  Apache 에서 제공하는 Connection Pool(DBCP : Data Base Connection Pool) 사용하기

- 기본적으로 Tomcat 5.5 이상 버전에서는 DBCP 가 포함되어 있기 때문에 별도로 다운로드 할 필요는 없다.

 

: 필요한 라이브러리 - Tomcat은 아래 jar파일 3개를 할 필요없고 Tomcat -dbcp만 필요하다. 

commons-collections-3.2.1.jar

commons-dbcp-1.4.jar

commons-pool-1.6.jar

 

2_3_2) JNDI작업

Context ctx = new InitialContext();

InitialContext객체 생성(Context 를 상속 받음)

JNDI 서비스를 제공하는 객체를 생성한다. 리소스가 로컬에 있을 경우 ContextInitialize 객체를 생성하는 것만으로 JNDI서비스를 할 수 있다.

 

DataSource source = (DataSource)ctx.lookup("java:comp/env/jdbc/oracle");

java:comp/env 는 톰캣에서 리소스를 관리하는 가상의 디렉터리 주소이다. "jdbc/jsp"는 context.xml에 등록한 자원의 이름이다. 

Context객체(JNDI 서비스)는 lookup 매서드의 매개변수를 "이름"으로 참고해 해당하는 자원의 "객체"를 반환해 준다. 이 객체는 Object타입을 반환하기 때문에 DataSource로 캐스팅해 사용한다.

 

2_3_3) Connection 얻어오기

Connection Connection conn = source.getConnection();

커넥션 풀에 대기 중인 커넥션 객체를 빌려오는 작업이다. 이후 작업은 JDBC와 동일하다.

 

 

2_3_3) Connection 반납

if(conn != null){ conn.close(); }

커넥션 풀에 사용한 커넥션 객체를 다시 반납해 줘야 한다.(여기서는 메모리 해제가 아님)

 

Path 

~~~;~~~;C:\Program Files\Java\jdk1.8.0_241\bin

~~~,~~~;%JAVA_HOME%bin

 

 

 

 

 

반응형

'백엔드 > JSP' 카테고리의 다른 글

JSESSIONID  (0) 2020.07.07
기초- JSP프로젝트 구조  (0) 2020.06.16
MVC  (0) 2020.06.16
Cookie 와 Session  (0) 2020.06.10
JSP DIRECTIVE - JSP include directive  (0) 2020.06.10
Comments