멋쟁이v의 개발일지

[Spring] Mybatis(커넥션 풀, log4jdbc) 본문

0년차/Spring

[Spring] Mybatis(커넥션 풀, log4jdbc)

멋쟁이v 2023. 6. 26. 20:39
728x90
320x100


01. 커넥션 풀

💡
JNDI, DBCP 활용하여 DB에 연동할 수 있다.
  • JNDI와 DBCP란?
    👉🏻
    JNDI(Java Naming and Directory Interface)

    ➡️ 디렉터리 서비스에서 제공하는 데이터 및 객체를 발견하고 참고하기 위한 자바 API

    ➡️ 외부에 있는 객체를 가져오기 위한 기술 ex) context.xml

    👉🏻
    DBCP(Database Connection Pool)

    ➡️ 데이터베이스와 연결된 커넥션을 미리 만들어서 저장해두고 있다가 필요할 때 저장된 공간(pool)에서 가져다 쓰고 반환하는 기법

    ➡️ 데이터베이스 연결과 해제 직접 관리

  • DBCP 구성

    ➡️ 커넥션 : 프로그램이 실행되기 전에 미리 생성된다. (Factory에서)

    ➡️ 사용자에게 빌려줬다가 회수했다가를 반복한다.

  • DBCP 특징

    1️⃣ 풀 속에 미리 connection 객체가 생성되어 있기 때문에 connection을 생성하는데 드는 연결 시간이 소비되지 않는다.

    2️⃣ connection을 계속해서 재사용하기 때문에 생성되는 connection 수가 많지 않다.

    3️⃣ 한 번에 생성될 수 있는 connection 수를 제어하기 때문에 동시 접속자 수가 몰려도 웹 어플리케이션이 쉽게 다운되지 않는다.

  • DBCP를 사용하는 이유

    ➡️ JDBC 예시

    Connection conn = null;
    PreparedStatement  pstmt = null;
    ResultSet rs = null;
    
    try {
    
        // 1. 드라이버 연결 DB 커넥션 객체를 얻음
        String jdbcDriver = "jdbc:mysql://localhost:3306/db?" + 
    					"useUnicode=true&characterEncoding=euckr";
    		String dbUser = "id";
    		String dbPass = "pw";
    		conn = DriverManager.getConnection(jdbcDriver, dbUser, dbPass);
    
        // 2. 쿼리 수행을 위한 PreparedStatement 객체 생성
        pstmt = conn.prepareStatement("SELECT * FROM tb_user");
    
        // 3. executeQuery: 쿼리 실행 후
        // ResultSet: DB 레코드 ResultSet에 객체에 담김
        rs = pstmt.executeQuery();
    
        } catch (Exception e) {
        } finally {
            conn.close();
            pstmt.close();
            rs.close();
        }
    }
    👉🏻
    자바에서 DB에 직접 연결해서 처리하는 경우(JDBC) 드라이버(Driver)를 로드하고 커넥션(connection) 객체를 받아와야 한다.

    그러면 매번 사용자가 요청을 할 때마다 드라이버를 로드하고 커넥션 객체를 생성하여 연결하고 종료하기 때문에 매우 비효율적이다.

    이러한 문제를 해결하기 위해 DBCP를 사용한다.

02. spring boot log4jdbc 설정

  • log4jdbc 종속성 추가
    💡
    pom.xml
    <dependency>
        <groupId>org.bgee.log4jdbc-log4j2</groupId>
        <artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
        <version>1.16</version>
    </dependency>

  • log4jdbc.log4j2.properties 설정
    💡
    필수항목 ➡️ log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator

    선택항목 (sql 쿼리를 몇줄 출력?) 0 -> 전체 sql쿼리문 노출 ➡️ log4jdbc.dump.sql.maxlinelength=0 드라이버 자동 로드 취소(생략가능) ➡️ #log4jdbc.auto.load.popular.drivers=false

  • application.properties 설정
    💡
    DB 연결 설정

    ➡️ spring.datasource.driver-class-name=net.sf.log4jdbc.sql.jdbcapi.DriverSpy

    ➡️ spring.datasource.url=jdbc:log4jdbc:mysql://localhost:3306/db명?serverTimezone=UTC&characterEncoding=UTF8

    ➡️ spring.datasource.username=db접속 아이디

    ➡️ spring.datasource.password=db접속 비밀번호

    mybatis 연동 설정

    ➡️ mapper 파일 경로 설정

    mybatis.mapper-locations=classpath:mapper.xml경로

    (classpath → scr/main/resources/ 까지의 경로)

    ➡️ dto 패키지 설정

    mybatis.type-aliases-package=dto패키지경로

  • logback.xml 추가
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
    	<!-- property : 변수 지정 -->
    	<property name="LOG_DIR" value="src/main/resources/logs" />
    	<property name="LOG_PATH_NAME" value="${LOG_DIR}/application.log" />
    
    	<!-- appender : pattern 대로 로그를 찍어낸다. -->
    	<!-- 콘솔 appender -->
    	<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    		<encoder>
    			<pattern>%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</pattern>
    		</encoder>
    	</appender>
    	<!-- 쿼리 콘솔 appender -->
    	<appender name="QSTDOUT" class="ch.qos.logback.core.ConsoleAppender">
    		<encoder>
    			<pattern>%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} %n    %msg%n</pattern>
    		</encoder>
    	</appender>
    
    	<!-- Rolling File Appender
        <appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            	파일 경로
            <file>${LOG_PATH_NAME}</file>
            	출력패턴
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</pattern>
            </encoder>
            Rolling 정책
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${LOG_DIR}/application.%d{yyyy-MM-dd}_%i.log</fileNamePattern>
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    	파일당 최고 용량 10MB
                    <maxFileSize>10MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
                	일자별 로그파일 최대 보관주기(일단위)만약 해당 설정일 이상된 파일은 자동으로 제거
                <maxHistory>30</maxHistory>
            </rollingPolicy>
        </appender> -->
    
    	<!-- logger : 최상위 루트, 코어 -->
    	<!-- 프로젝트 패키지 안 클래스에 설정된 로그 출력, level=off하면 로그가 하나도 안보인다. -->
    	<logger name="패키지명" level="INFO" additivity="false">
    		<appender-ref ref="STDOUT" />
    	</logger>
    	<!-- 아직 싱글톤 안나가서 하지 않는 것이 맞음 -->
    	<logger name="org.springframework" level="OFF" additivity="false">
    		<appender-ref ref="STDOUT" />
    	</logger>
    
    	<!-- log4jdbc 옵션 설정 -->
    	<logger name="jdbc" level="OFF" additivity="false">
    		<appender-ref ref="STDOUT" />
    	</logger>
    
    	<!-- 커넥션 open close 이벤트를 로그 -->
    	<logger name="jdbc.connection" level="OFF" additivity="false">
    		<appender-ref ref="STDOUT" />
    	</logger>
    
    	<!-- SQL문만을 로그로 남기며, PreparedStatement일 경우 관련된 argument 값으로 대체된 SQL문 출력 -->
    	<logger name="jdbc.sqlonly" level="OFF" additivity="false">
    		<appender-ref ref="STDOUT" />
    	</logger>
    
    	<!-- SQL문과 해당 SQL을 실행시키는데 수행된 시간 정보(milliseconds)를 포함하여 출력. -->
    	<logger name="jdbc.sqltiming" level="INFO" additivity="false">
    		<appender-ref ref="QSTDOUT" />
    	</logger>
    
    	<!-- ResultSet을 제외한 모든 JDBC 호출 정보를 로그 출력, 많은 양의 로그가 생성되므로 특별히 JDBC 문제를 추적해야 할 필요가 있는 경우를 제외하고는 권장 안함. -->
    	<logger name="jdbc.audit" level="OFF" additivity="false">
    		<appender-ref ref="STDOUT" />
    	</logger>
    
    	<!-- ResultSet을 포함한 모든 JDBC 호출 정보를 로그로 남기므로 매우 방대한 양의 로그가 생성된다. -->
    	<logger name="jdbc.resultset" level="OFF" additivity="false">
    		<appender-ref ref="STDOUT" />
    	</logger>
    
    	<!-- SQL 결과 조회된 데이터의 table로 표현하여 로그 출력 -->
    	<logger name="jdbc.resultsettable" level="INFO" additivity="false">
    		<appender-ref ref="STDOUT" />
    	</logger>
    
    	<!-- root는 글로벌 로거를 의미하며, 위의 logger에 해당하지 않으면 root 로거가 실행 -->
    	<root level="ERROR">
    		<appender-ref ref="STDOUT" />
    	</root>
    </configuration>

  • spring boot LogBack
    💡
    Log4j를 만든 개발자가 Log4j 기반으로 더 빠른 속도와 더 적은 메모리 점유율 등의 성능을 개발하여 만든 Logging Framework이다.
    • 특징

      ➡️ Level

      로그에 레벨을 설정할 수 있다. 로그마다 레벨을 설정해두고, 설정 파일에서 출력 로그 레벨을 설정하여 원하는 단계의 로그만 출력할 수 있다.

      ➡️ Appender

      출력 방법을 선택할 수 있다. 로그의 기록을 담당하는 Appender에게 출력 위치(콘솔, 파일 등)나 출력 내용(날짜/시간, 레벨 등)에 대한 패턴을 설정할 수 있다.

      📌
      ConsoleAppender: 콘솔에 로그를 기록하는 방법

      FileAppender: 파일에 로그를 기록하는 방법

      RollingFileAppender: 여러 개의 파일을 순회하며 로그를 기록하는 방법

      SMTPAppender: 로그를 메일로 기록하는 방법

      DBAppender: 데이터베이스에 로그를 기록하는 방법

      ➡️ Logger

      로그마다 다른 설정 내용을 쉽게 적용시킬 수 있다. Logger에 이름을 부여하여 필요한 상황에 맞게 적절한 Logger를 호출하여 사용할 수 있다.

      ➡️ Log Level

      📌
      ERROR: 요청을 처리하는 중 오류가 발생한 경우 표시한다.

      WARN: 처리 가능한 문제, 향후 시스템 에러의 원인이 될 수 있는 경고성 메시지를 나타낸다.

      INFO: 상태변경과 같은 정보성 로그를 표시한다.

      DEBUG: 프로그램을 디버깅하기 위한 정보를 표시한다.

      TRACE: 추적 레벨은 Debug보다 훨씬 상세한 정보를 나타낸다.

      ➡️ root

      root는 글로벌 로거를 의미하며, 위의 logger에 해당하지 않으면 root 로거가 실행

03. Mybatis란?

💡
MyBatis는 객체 지향 언어인 Java의 관계형 데이터베이스 프로그래밍을 좀 더 쉽게 도와주는 퍼시스턴스 프레임워크(Persistence Framework, 데이터를 다루는 클래스 및 설정파일 집합)이다.

MyBatis는 JDBC를 통해 RDBMS에 액세스하는 작업을 캡슐화하고 기존 JDBC의 중복작업을 간소화해준다.

또한, XML 파일의 형태인 mapper를 통해 프로그램 코드로부터 SQL 쿼리를 분리되는 환경을 제공하고 Java 객체와 매핑하는 작업을 도와준다.

  • 특징
    • 기존 JDBC보다 사용하기 편리
    • 다른 ORM(Object Relational Mapping) 프레임워크에 비해 추가적인 학습의 부담이 적음
    • 복잡한 쿼리 또는 다이나믹한 쿼리를 지원
    • 프로그램 코드와 SQL 쿼리의 분리로 인한 간결성 및 유지보수성 향상
    • 빠른 개발과 생산성의 향상

  • ORM vs SQL Mapper
    👉🏻
    ORM(Object Relational Mapping)
    • 객체와 관계형 데이터베이스의 데이터를 매핑해주는 것.

    ➡️ 장점

    • 객체 모델만을 이용하고, 객체지향적으로 프로그래밍이 가능하다.
    • SQL을 직접 작성하지 않아도 된다. (개발 시간 단축)
    • 유지보수가 용이하다.
    • DBMS에 종속되어 있지 않다.

    ➡️ 단점

    • 데이터의 관계가 복잡할수록 구현하기 어렵다.
    • 복잡한 SQL문을 처리하기 어렵다.

    👉🏻
    SQL Mapper (Mybatis)
    • 객체와 SQL문을 매핑하여 데이터를 객체화하는 기술이다.

    ➡️ 장점

    • 관계를 정확히 명시한다.
    • 복잡한 SQL문도 처리한다.

    ➡️ 단점

    • SQL 구문을 직접 작성해야 한다.
    • 유지보수가 하락된다.
    • DBMS에 종속되어 있다.

  • DB Access Architecture
    👉🏻
    기존 JDBC 프로그래밍의 경우 Repository에서 곧바로 JDBC API 쪽으로 접근하여 DB를 연결하였지만,

    MyBatis를 사용할 경우 Repository와 JDBC API사이에 MyBatis가 위치함으로서 편리한 Access를 제공한다.

  • DB Access 순서
    👉🏻
    어플리케이션 실행 시 프로세스

    1) 어플리케이션이 SqlSessionFactoryBuilder에게 SqlSessionFactory를 빌드하도록 요청한다.

    2) SqlSessionFactoryBuilder는 SqlSessionFactory를 생성하기 위해 MyBatis 설정 파일을 읽는다.

    3) SqlSessionFactoryBuilder는 MyBatis 설정 파일의 정의에 따라 SqlSessionFactory를 생성한다.

    클라이언트 요청 시 프로세스

    4) 클라이언트의 어플리케이션에 대한 요청한다.

    5) 어플리케이션은 SqlSessionFactoryBuilder를 사용하여 빌드된 SqlSessionFactory에서 SqlSession을 가져온다.

    6) SqlSessionFactory는 SqlSession을 생성하고 이를 어플리케이션에 반환한다.

    7) 어플리케이션이 SqlSession에서 Mapper Interface 구현 개체를 가져온다.

    8) 어플리케이션이 Mapper Interface의 메소드를 호출한다.

    9) Mapper Interface의 구현 개체가 SqlSession 메소드를 호출하고 SQL 실행 요청한다.

    10) SqlSession은 Mapping File에서 실행할 SQL을 찾아서 실행한다.

04. Mybatis 종속성 추가

  • pom.xml 설정
    💡
    기존에 사용한 종속성

    ➡️ Spring Boot DevTools

    ➡️ Spring Web

    ➡️ Thymeleaf

    DB연결을 위한 추가 종속성

    ➡️ MySQL Driver

    ➡️ Spring Data JDBC

    ➡️ MyBatis Framework


tag : #Spring #Mybatis #JNDI #DBCP #커넥션풀 #log4j #log4jdbc #logback #logger #종속성 #SQL Mapper


Uploaded by N2T

728x90
320x100
Comments