[Java] DB연동과 Connection Pool

Connection Pool을 사용하는 이유

  • 자바 프로그램에서 DBMS로 커넥션을 생성하려면 시간이 많이 걸린다.
  • 사용자가 접속할 때마다 커넥션을 생성하면 오버헤드가 발생할 수 있다.
  • 그래서 웹 어플리케이션을 실행함과 동시에 커넥션 풀에 일정 개수의 DB 커넥션을 미리 만들어둔다. (Pool - 서버에 이미 내장된 메모리)
  • 요청을 처리하는 각 스레드에서 커넥션을 생성하지 않고, 커넥션풀의 커넥션 객체를 할당받아 사용한 뒤 반납한다

img

[이미지 출처] https://devbox.tistory.com/entry/JSP-%EC%BB%A4%EB%84%A5%EC%85%98-%ED%92%80-1

Connection Pool 만들기

(1) DataSource

  • 자바 웹 어플리케이션에서 커넥션풀 객체를 구현하기 위한 스펙을 정의해놓은 인터페이스 = javax.sql.DataSource
  • DataSource 객체에 DB연결에 필요한 URL, ID, Password, DriverClass를 미리 정의해놓고 사용한다 - DB연결시마다 해당 정보를 매번 입력해야 하는 번거로움 해소

(2) JNDI (Java Naming and Directory Interface)

  • 분산된 객체를 찾기위해 특정한 이름으로 객체를 등록해서 관리할 수 있게 해주는 자바 API
  • Tomcat과 같은 WAS에서는 특정 폴더에 필요한 데이터 소스(라이브러리)가 있는데 그것을 사용하기 위해 JNDI 기술을 활용한다.
  • 미리 지정한 이름(name)을 찾아서(lookup) 활용하면 된다.
  • Initialcontext는 JNDI namespace의 모든 명명된 객체를 찾을 때 사용하는 객체

💎 Tomcat에서 JNDI 활용해서 DB연결하기

  • context.xml 파일에 커넥션풀을 만드는 DataSource 리소스를 등록한다.
  • JNDI기술을 통해 해당 리소스의 이름을 가져와서 사용한다.
  • DataSource는 사용자 요청이 있을 때마다 Connection을 제공한다.

웹 프로젝트에서 DB 연동하기

1) JDBC 사용

  1. JDBC Driver 설정

    • 오라클 11g xe 기준 -ojdbc6.jar파일을 WebContent\WEP-INF\lib 폴더에 넣는다
  2. 커넥션풀에 대한 정보를 DataSource에 설정

    • 첫번째 방법) Servers\Tomcat v9.0 Server at localhost-config\context.xml 파일에 설정해도 되고,
    • 두번째 방법) Servers\Tomcat v9.0 Server at localhost-config\context.xml을 복사해서 현 프로젝트의 META-INF 하단에 붙여넣기 후 편집해도 된다.

    프로젝트마다 설정하는 것이 더 안정적이므로 두번째 방법으로 하겠다.


    <META-INF \ context.xml>

    <?xml version="1.0" encoding="UTF-8"?>
    <Context>
    	<Resource name="jdbc/myoracle" 
                 auth="Container"
                 type="javax.sql.DataSource" 
                 driverClassName="oracle.jdbc.OracleDriver"
                 url="jdbc:oracle:thin:@127.0.0.1:1521:xe"
                 username="SCOTT" password="TIGER" 
                 maxTotal="20" 
                 maxIdle="10"
                 maxWaitMillis="-1"/>
    </Context>

    위와 같이 이렇게 이름이 “jdbc/myoracle”이고, 종류는 DataSource인 resource를 생성하였다.


    ✅ Resource 설정값 설명

    커넥션풀 설정값 설명
    initialSize 최초로 커넥션풀 생성 시 만들 Connection 객체의 수 (기본값 0)
    minIdle 최소한으로 유지될 Connection 객체의 수 (기본값 0)
    maxIdle 커넥션풀에 반납된 유휴 Connection 객체를 유지할 수 있는 최대값 (기본값 8)
    maxTotal (= maxActive) 동시에 사용할 수 있는 최대 커넥션 갯수 (기본값 8)
    maxWaitMillis (=maxWait) 할당받을 Connection 객체가 없을 때 스레드를 블록시킬 시간 (1/1000초 단위) / -1 : 무한 대기 의미

  3. .java 혹은 .jsp 파일에서 사용

    <DButil.java>

    package util;
    
    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import javax.sql.DataSource;
    import java.sql.Connection;
    
    public class DBUtil {
    
    	// datasource는 static 멤버변수로 설정 - 하나의 객체만 생성
       private static DataSource ds;   
    	
    	static {
    		try {
               // InitialContext가 생성되면서 context.xml에 저장된 정보를 읽어온다
               Context initContext = new InitialContext(); 
    			
               // "java:/comp/env" = java environment상의 component(=재사용 가능한 객체)
               // 자바 실행환경 내부에 저장된 자원을 검색해서 사용하겠다는 뜻
               Context envContext  = (Context)initContext.lookup("java:/comp/env");  
    			
               // "jdbc/myoracle" 이름으로 되어있는 자원(즉 Datasource)을 ds라는 변수명으로 사용
               ds = (DataSource)envContext.lookup("jdbc/myoracle");
               
           } catch (NamingException e) {
               e.printStackTrace();
           }
    		
    	}
    
    	// getConnection() 메소드 실행시마다 커넥션풀로부터 커넥션 받아오는 메소드
    	public static Connection getConnection() throws SQLException {
           return ds.getConnection();  
       }
    
    }

2) JPA 사용

  1. 프로젝트를 JPA 프로젝트로 변환
  2. 프로젝트를 Maven 프로젝트로 변환

    • pom.xml 설정파일 수정하여 oracle Driver 등록 및 javax.persistence, org.hibernate 등록
    • lombok, slf4j 등등도 등록해서 사용
  3. persistence.xml 설정파일 수정 (1~3번 과정 이전 포스팅 참고 - [Java] 12. JPA )
  4. .java 혹은 .jsp 파일에서 사용

    <DBUtil.java>

    package util;
    
    import java.sql.SQLException;
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.Persistence;
    
    public class DBUtil {
       private static EntityManagerFactory emf;
       
       static {
           emf = Persistence.createEntityManagerFactory("myoracle");
           // EntityManagerFactory는 웹어플리케이션이 로딩되는 시점에 딱 한개만 생성
           // 사용자 요청시마다(=스레드 하나 생성될때마다) EntityManager를 생성, 관리
           // JDBC의 Connection Pool과 같다고 생각하면 됨
       }
       
       public static EntityManager getEntityManager() throws SQLException {
           return emf.createEntityManager();
           // EntityManager는 스레드 간에 공유되지 않음
           // 엔티티와 관련된 모든 일(CRUD) 처리
           // JDBC의 Connection 객체와 같다고 생각하면 됨
       }
       
       public static void close() {
           emf.close();
           emf = null;
       }
    
    }

Written by@[hyem]
Hyem's Dev Note

GitHub