2021-07-14강의록_커넥션 풀(Data Source)

MIN.DI·2021년 7월 14일
0

강의록

목록 보기
33/54

데이터소스(Data Source)

  1. 패키지: javax.sql.DataSource interface
  2. 이 인터페이스의 구현객체는, WAS가 만들어 제공
  3. 이 DataSource 객체는 Connection Pool 기능을 제공
  4. 개발자: 아래의 2가지 작업을 해야 함.
    (1) DataSource 설정 필요
    (2) 설정이 끝난 DataSource 구현 객체를 얻어야 함.
    (방법2가지: @Resource, JNDI)
  5. Connection Pool: 대량의 트랜잭션 처리의 핵심기능(⭐⭐⭐⭐)
    • 예: 국세청의 연말정산 웹서비스(동시유저: 50 ~ 60만)
  6. 스프링에서도 당연히, 데이터소스로 대량의 트랜잭션 처리

@Resource 어노테이션의 약점

:어노테이션 통한 JNDI TREE의 자원객체 획득 방법은, 오로지 Servlet Class내에서만 유효함.
일반적인 다른 클래스에서 자원객체를 얻어오려면, JNDI Lookup 을 해야 한다.


<Context>

    <!-- url="jdbc:oracle:thin:@localhost:1521/seoul" -->
    
    <!-- cloud가 아닌 local db 사용시 -->
    <!-- maxActive deprecared -->
    <!-- <Resource 
        name="jdbc/OracleLocalDB" 
        auth="Container"
        type="javax.sql.DataSource"
        username="scott"
        password="oracle"
        driverClassName="oracle.jdbc.OracleDriver"
        url="jdbc:oracle:thin:@seoul?TNS_ADMIN=C:/u01/oracle/product/19.3.0/dbhome/network/admin"
        maxTotal="8"
        maxIdle="2"
        loginTimeout="1"
    /> -->
      <!-- name="jdbc/~~~~" 가 관례임
        auth="Container" :인증은 WAS가 대신하겠다. 
        maxTotal 개수만큼 connection을 만들 수 있음 (connection pool. 개발자가 생성하는것이 아니라 WAS가 생성.)
        maxIdle = 2초 이상 아무도 커넥션을 이용하지 않으면 자동으로 줄어듦. == Shrinking
        longinTimeout : 로그인이 1초 안에 이루어지지 않으면 예외를 발생시킴.
    
        하나의 커넥션을 가져다 쓰고, 다시 pool에 넣어놓는 재사용.
        적은 수의 커넥션 만으로도 대량의 트랜잭션을 처리할 수 있다.-->
    

    
    <!-- cloud db 에서 driverSpy 사용하지 않을 떄 -->
    <!-- maxActive deprecared -->
    <Resource
        name="jdbc/OracleCloud" 
        auth="Container"
        type="javax.sql.DataSource"
        username="SCOTT"
        password="Oracle12345!!!"
        driverClassName="oracle.jdbc.OracleDriver"
        url="jdbc:oracle:thin:@db202106301639_high?TNS_ADMIN=C:/opt/OracleCloudWallet/ATP"
        maxTotal="8"
        maxIdle="2"
        loginTimeout="1"
    />
  

    <!-- cloud db에서 driverSpy 사용할 때 -->
    <!-- maxActive deprecared -->
    <!-- <Resource 
        name="jdbc/OracleCloudWithLog4jdbc" 
        auth="Container"
        type="javax.sql.DataSource"
        username="SCOTT"
        password="Oracle12345!!!"
        driverClassName="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"
        url="jdbc:log4jdbc:oracle:thin:@sdb202106301639_high?TNS_ADMIN=C:/u01/oracle/product/19.3.0/dbhome/network/admin"
        maxTotal="8"
        maxIdle="2"
        loginTimeout="1"
    /> -->

</Context>    

JNDI : Java Naming & Directory Interface

J2EE의 주요 인터페이스.
-> Was 에 우리가 사용한 DataSource리소스 객체같은 다양한 타입의 객체를
JNDI tree에 올려놓고,
-> JNDI lookup 이라는 행위를 통해, JNDI tree에 올려놓은 다양한 자원객체를 얻는 표준 방법
Was라는 컨테이너가 있고, 이 안에 나무가 있다고 생각하자.
뿌리로부터 줄기가 올라와서 가지를 치고, 사과가 열렸다.
이 사과가 자원객체임.
이렇게 사과(자원객체)를 올려놓는 행위가 곧 Binding. 나뭇가지에 사과를 묶어놓는 것.
바인딩 할 때 각각의 자원객체에는 이름을 붙여준다. (context.xml파일에서 설정)
이 나무를 탐색해서, 내가 원하는 이름속성의 사과를 찾을 때
@Resource어노테이션의 name속성을 가지고 찾아옴. => 이렇게 검색하는 행위가 lookup임.


import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;


@Log4j2
@NoArgsConstructor

@WebServlet("/EmpInsert")
public class EmpInsertServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	
//	@Resource(name="jdbc/OracleCloud")
	private DataSource ds;
	
	private String sql = "INSERT INTO emp(empno, ename, sal, deptno) VALUES (?,?,?,?)";
       
	@Override
	public void init(ServletConfig config) throws ServletException{
		log.debug("init(config) invoked.");
		
		
		// 2. JNDI lookup을 통해 DataSource 객체를 얻고, Connection Pool을 사용하기
		Context ctx = null;	//자원객체이므로 반드시 사용이 끝나면 close 해줘야 함.
					//단, 이 context 인터페이스는 AutoClosable하지 않으므로 직접 close해주어야 함.
		
		try {
			// 2-1. JNDI tree의 뿌리(root)를 먼저 접근
			ctx = new InitialContext();
			log.info("\t ctx: " + ctx);
			
			// 2-2. JNDI root를 통해 JNDI tree를 looup 해야 함.
			//		자원객체의 이름 지정은 표준화 되어있음.
			//		java:comp/env/자원객체이름
//			Object obj = ctx.lookup("java:comp/env/jdbc/OracleCloud");
			Object obj = ctx.lookup("java:comp/env/jdbc/OracleCloud");
			this.ds = (DataSource)obj;
			
			log.info("\t ds: " + ds);
					
		}catch(Exception e) {
			throw new ServletException(e);
			
		}finally {
			if(ctx != null) {
				try {ctx.close();}
				catch(NamingException e) {;;} //try-catch
			} //if
		} //try-catch-finally
	}//init
	
   
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse res) 
			throws ServletException, IOException {
		log.debug("service(req,res) invoked.");
		
		try {
			// 1. 웹 브라우저에서 전송한 파라미터들을 획득
			String empno = req.getParameter("empno");
			String ename = req.getParameter("ename");
			String sal = req.getParameter("sal");
			String deptno = req.getParameter("deptno");
			
			// 2. DataSource(Connection Pool)로부터 Connection 얻기
			Connection conn = ds.getConnection();				//자원객체 1
			
			// Binding작업 수행
			PreparedStatement pstmt = conn.prepareStatement(sql);		//자원객체 2
			pstmt.setInt(1, Integer.parseInt(empno));	
			pstmt.setString(2, ename);
			pstmt.setDouble(3, Double.parseDouble(sal));
			pstmt.setInt(4, Integer.parseInt(deptno));
			
			int affectedLines = pstmt.executeUpdate();
			
			// 3. 응답문서 준비
			res.setContentType("text/html; charset=utf8");
			PrintWriter out = res.getWriter();				//자원객체 3
			
			try(conn; pstmt; out;){		//connection을 끊는것이 아니라 connection pool로 반납하는 것!
				
				if(affectedLines>0) {
					out.println("저장 성공");
					
				}else {
					out.println("저장 실패");
					
				} //if-else
				
				out.flush();
			}//try-with-resources
			

		} catch (Exception e) {
			throw new ServletException(e);
		} //try-catch
		
	} //service(req, res)

} //end class

HikariCP

HikariCP ==> javax.sql.DataSource의 구현객체 제공

profile
내가 보려고 쓰는 블로그

0개의 댓글