들어가기 전에
이번에 프로젝트를 본격적으로 시작하면서 MyBatis 설정을 끝냈는데 혹시나 다음 번에 설정해야 할 일이 있을 때 내가 정리한 문서를 참고하기 위해서 기록해 보기로 했다. log4jdbc-log4j2도 처음 알게 된 라이브러리인데 도움이 될 것 같아서 같이 정리하려고 한다.
log4jdbc-log4j2
Log4jdbc-log4j2
This project was imported from https://code.google.com/archive/p/log4jdbc-log4j2/ Original License: Apache License 2.0 log4jdbc-log4j2 is a modification of log4jdbc to natively use Log4j 2 (or SLF4J as usual), that supports JDBC 4.1 to JDBC 3, includes all
log4jdbc.brunorozendo.com
SQL문을 실행할 때 관련 정보를 로깅할 수 있는 JDBC 라이브러리이다. Maven repository에서 검색해 보거나 위의 사이트를 들어가면 바로 2013년이라는 날짜가 보여서 나처럼 정보를 잘못 찾은 건가 당황할 수 있지만 이게 맞다. 굉장히 오래 전에 업데이트가 되고 이후로는 되지 않았지만 아직도 잘 쓰이고 있는 것 같다.
아래와 같이 입력된 정보를 UI적으로 편하게 볼 수 있도록 해주기도 하고 혹은 쿼리문의 형태, Connection 정보까지 많은 기록들을 로그로 확인할 수 있다.
시작하기
1. 의존성 추가
implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16'
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.1'
runtimeOnly 'com.mysql:mysql-connector-j'
testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:3.0.1'
- log4jdbc-log4j2
- mybatis, mybatis-test
- 사용하는 DB 관련 의존성
2. application.yml
spring:
datasource:
driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
url: jdbc:log4jdbc:[DB]://[HOST]:[PORT]/[DATABASE]?useSSL=false
username: [USERNAME]
password: [PASSWORD]
logging:
level:
jdbc:
sqlonly: off
sqltiming: debug
audit: off
resultset: off
resultsettable: debug
connection: off
mybatis:
mapper-locations: mapper/**/*.xml
configuration:
[설정 정보 등록]
❶ datasource 설정
- driver-class-name은 net.sf.log4jdbc.sql.jdbcapi.DriverSpy으로 지정해야 한다.
- useSSL=false 설정은 MySQL의 SSL이 true로 설정되어있어 연결이 안되기 때문에 추가했다.
❷ logger 설정
6개의 logger가 있는데 모두 사용하지 않으면 실제 데이터베이스의 반환 값이 출력되고 하나라도 ERROR, INFO, DEBUG로 설정되면 log4jdbc가 활성화돼서 작업 내역을 로깅해 준다고 한다.
Logger | 설명 |
jdbc.sqlonly | SQL만 기록한다. 쿼리문에서 바인딩된 데이터로 대체된 인수가 표시된다. |
jdbc.sqltiming | SQL을 실행하는 데 걸린 시간에 대한 통계까지 포함하여 로깅한다. |
jdbc.audit | ResultSets를 제외한 모든 JDBC 호풀을 기록한다. 일반적으로 특정 JDBC 문제를 추적하지 않는 한 필요하지 않다. |
jdbc.resultset | ResultSet 개체에 대한 모든 호출이 기록된다. |
jdbc.resultsettable | JDBC 결과를 테이블로 기록한다. |
jdbc.connection | Connection에 관련된 정보로 누수 문제를 추적할 때 용이하다. |
❸ mybatis settings
- mapper-locations는 resources 하위에 mapper 파일들이 위치할 디렉토리를 명시해 주면 된다. 나는 resources 하위에 mapper 폴더를 만들었고 추후에 도메인 별로 나눌 가능성이 있을까봐 저렇게 지정해뒀다.
- configuration에는 여러 가지 정보들을 설정할 수 있다.
설정 | 설명 | 기본값 |
cacheEnabled | 설정에서 각 매퍼에 설정된 캐시를 전역적으로 사용할지 말지에 대한 여부 | true |
lazyLoadingEnabled | 지연로딩을 사용할지에 대한 여부. 사용하지 않는다면 모두 즉시 로딩할 것이다. 이 값은 fetchType 속성을 사용해서 대체할 수 있다. | false |
aggressiveLazyLoading | 활성화되면 모든 메서드 호출은 객체의 모든 lazy properties 을 로드한다. 그렇지 않으면 각 property 가 필요에 따라 로드된다. (lazyLoadTriggerMethods 참조). | false (3.4.1 부터 true) |
multipleResultSetsEnabled | 한 개의 구문에서 여러 개의 ResultSet을 허용할지의 여부(드라이버가 해당 기능을 지원해야 함) | true |
useColumnLabel | 컬럼명 대신에 컬럼라벨을 사용. 드라이버마다 조금 다르게 작동한다. 문서와 간단한 테스트를 통해 실제 기대하는 것처럼 작동하는지 확인해야 한다. | true |
useGeneratedKeys | 생성키에 대한 JDBC 지원을 허용. 지원하는 드라이버가 필요하다. true로 설정하면 생성키를 강제로 생성한다. 일부 드라이버(예를들면, Derby)에서는 이 설정을 무시한다. | false |
autoMappingBehavior | 마이바티스가 칼럼을 필드/프로퍼티에 자동으로 매핑할지와 방법에 대해 명시. PARTIAL은 간단한 자동매핑만 할뿐 내포된 결과에 대해서는 처리하지 않는다. FULL은 처리가능한 모든 자동매핑을 처리한다. | PARTIAL (NONE/PARTIAL/FULL) |
autoMappingUnknownColumnBehavior | 자동매핑 대상 중 알 수 없는 칼럼(이나 알 수 없는 프로퍼티 타입)을 발견했을 때 행위를 명시
|
NONE (NONE/WARNING/FAILING) |
defaultExecutorType | 디폴트 실행자(executor) 설정. SIMPLE 실행자는 특별히 하는 것이 없다. REUSE 실행자는 PreparedStatement를 재사용한다. BATCH 실행자는 구문을 재사용하고 수정을 배치처리한다. | SIMPLE(SIMPLE/REUSE/BATCH) |
defaultStatementTimeout | 데이터베이스로의 응답을 얼마나 오래 기다릴지를 판단하는 타임아웃을 설정 | 설정되지 않음 |
defaultFetchSize | 결과를 가져오는 크기를 제어하는 힌트처럼 드라이버에 설정한다. 이 파라미터는 쿼리설정으로 변경할 수 있다. | 설정되지 않음 |
defaultResultSetType | 각 구문의 설정을 생략할 때 스크롤 하는 방법을 지정한다. (3.5.2 부터) | 설정되지 않음(FORWARD_ONLY/SCROLL_SENSITIVE/SCROLL_INSENSITIVE/DEFAULT) |
safeRowBoundsEnabled | 중첩구문내 RowBound사용을 허용 허용한다면 false로 설정 | false |
safeResultHandlerEnabled | 중첩구문내 ResultHandler사용을 허용 허용한다면 false로 설정 | true |
mapUnderscoreToCamelCase | 전통적인 데이터베이스 칼럼명 형태인 A_COLUMN을 CamelCase형태의 자바 프로퍼티명 형태인 aColumn으로 자동으로 매핑하도록 함 | false |
localCacheScope | 마이바티스는 순환참조를 막거나 반복된 쿼리의 속도를 높히기 위해 로컬캐시를 사용한다. 디폴트 설정인 SESSION을 사용해서 동일 세션의 모든 쿼리를 캐시한다. localCacheScope=STATEMENT 로 설정하면 로컬 세션은 구문 실행할때만 사용하고 같은 SqlSession에서 두 개의 다른 호출 사이에는 데이터를 공유하지 않는다. | SESSION(SESSION/STATEMENT) |
jdbcTypeForNull | JDBC타입을 파라미터에 제공하지 않을때 null값을 처리한 JDBC타입을 명시한다. 일부 드라이버는 칼럼의 JDBC타입을 정의하도록 요구하지만 대부분은 NULL, VARCHAR 나 OTHER 처럼 일반적인 값을 사용해서 동작한다. | OTHER |
lazyLoadTriggerMethods | 지연로딩을 야기하는 객체의 메소드를 명시 | equals,clone,hashCode,toString |
defaultScriptingLanguage | 동적으로 SQL을 만들기 위해 기본적으로 사용하는 언어를 명시 | org.apache.ibatis.scripting.xmltags.XMLLanguageDriver |
defaultEnumTypeHandler | Enum에 기본적으로 사용되는 TypeHandler 를 지정합니다. (3.4.5 부터) | org.apache.ibatis.type.EnumTypeHandler |
callSettersOnNulls | 가져온 값이 null일 때 setter나 맵의 put 메소드를 호출할지를 명시 Map.keySet() 이나 null값을 초기화할때 유용하다. int, boolean 등과 같은 원시타입은 null을 설정할 수 없다는 점은 알아두면 좋다. | false |
returnInstanceForEmptyRow | MyBatis 는 기본적으로 모든 열들의 행이 NULL 이 반환되었을 때 null을 반환한다. 이 설정을 사용하면 MyBatis가 대신 empty 인스턴스를 반환한다. nested results(collection 또는 association) 에도 적용된다. 3.4.2 부터 | false |
logPrefix | 마이바티스가 로거(logger) 이름에 추가할 접두사 문자열을 명시 | 설정하지 않음 |
logImpl | 마이바티스가 사용할 로깅 구현체를 명시 이 설정을 사용하지 않으면 마이바티스가 사용할 로깅 구현체를 자동으로 찾는다. | 설정하지 않음(SLFJ2/LOG4J2/JDK_LOGGING/COMMONGS_LOGGING/STDOUT_LOGGING/NO_LOGGING) |
proxyFactory | 마이바티스가 지연로딩을 처리할 객체를 생성할 때 사용할 프록시 툴을 명시 | JAVASSISTS (MyBatis 3.3 이상 버전) |
vfsImpl | VFS 구현체를 명시 | |
useActualParamName | 메소드 시그니처에 명시된 실제 이름으로 구문파라미터를 참조하는 것을 허용 이 기능을 사용하려면 프로젝트를 자바 8의 -parameters옵션을 사용해서 컴파일해야만 한다.(마이바티스 3.4.1이상의 버전) | true |
configurationFactory | Configuration 인스턴스를 제공하는 클래스를 지정한다. 반환된 Configuration 인스턴스는 역직렬화 된 객체의 지연로딩 속성들을 불러오는 데 사용된다. 이 클래스는 static Configuration getConfiguration() 메서드를 가져야 한다. (3.2.3 부터) | 설정하지 않음 |
shrinkWhitespacesInSql | SQL에서 여분의 whitespace 문자들을 삭제한다. 이는 SQL의 리터럴 문자열에도 영향을 미친다. (Since 3.5.5) | false |
defaultSqlProviderType | Provider method를 가지고 있는 sql provider class를 지정한다. (3.5.6 부터). 이 클래스는 sql provider annotation(예: @SelectProvider)의 type (혹은 value)속성이 누락되었을때 기본으로 적용된다. | 설정하지 않음 |
nullableOnForEach | 'foreach' 태그에서 'nullable' 속성의 기본값을 지정한다. (3.5.9 부터) | false |
argNameBasedConstructorAutoMapping | 생성자 자동 매핑을 적용할 때 칼럼 순서가 아닌 칼럼 이름과 생성자 인수들의 이름을 기반으로 매핑한다. (3.5.10 부터) | false |
3. log4jdbc.log4j2.properties
log4jdbc.log4j2의 속성 파일을 만들어야 하는데 기본값은 properties였지만 가독성을 위해 yml로 변경했었는데 설정값이 적용이 안돼서 다시 properties로 변경했다.
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
log4jdbc.dump.sql.maxlinelength=0
log4jdbc.drivers=com.mysql.cj.jdbc.Driver
log4jdbc.auto.load.popular.drivers=false
- spylogdelegator.name : 4jdbc-log4j2 기능을 사용하기 위해 사용할 클래스 이름을 지정해준다. 참고로 다른 값은 없이 무조건 net.sf.log4jdbc.log.slf4j.Sl4jSpyLogDelegator로 설정해야 한다.
- dump.sql.maxlinelength : 기본값이 90이기 때문에 제한없이 출력하기 위해 0으로 설정한다.
- Mysql을 사용하는 경우, drivers에는 com.mysql.jdbc.Driver만 등록되어있기 때문에 auto.load.popluar.drivers를 false로 설정하고 drivers를 com.mysql.cj.jdbc.Driver로 설정해야 한다. 아마 이 라이브러리가 계속해서 업데이트되고 있지 않기 때문에 드라이버도 업데이트되지 않은 것 같다. 설정하지 않으면 아래와 같은 메시지를 만날 수 있다.
나같은 경우에는 yml 파일로 만들고 나서 설정값을 제대로 작성했는데도 사라지지 않아 properties로 변경했는데 그제서야 이 메시지가 사라지게 됐다.
속성 | 설명 | 기본값 |
log4jdbc.drivers | 둘 이상의 드라이버를 지정해야 하는 경우 공백 없이 쉼표로 구분해야 한다. 대부분의 유명한 JDBC 드라이버는 기본적으로 이미 로드되어 있기 때문에 이 옵션은 일반적으로 필요하지 않다. log4jdbc가 아직 래핑하지 않은 하나 이상의 추가 JDBC 드라이버를 포함해야 하는 경우 이 옵션을 사용해야 한다. | |
log4jdbc.auto.load.popular.drivers | 자주 사용되는 드라이버가 자동으로 로드되는 기능을 비활성화하려면 false로 설정한다. false이면 드라이버를 로드하기 위해 log4jdbc.drivers 속성을 설정해야 한다. | true |
log4jdbc.debug.stack.prefix | 어플리케이션 패키지 이름과 일치하는 regex로 설정되지 않을 경우 log4jdbc로 호출된 실제 클래스가 디버그 출력에 사용된다. | |
log4jdbc.sqltiming.warn.threshold | 밀리초 시간 값을 지정하며 지정된 시간 또는 실행하는 데 더 많은 시간이 걸리는 SQL이 sqltiming 로그에 경고 수준으로 기록된다. 이 기능을 작동하게 하려면 sqltiming 로그를 활성화해야 한다. 그리고 로깅 레벨이 DEBUG로 활성화되어야 한다. | |
log4jdbc.sqltiming.error.threshold | 밀리초 시간 값을 지정하며 지정된 시간 또는 실행하는 데 더 많은 시간이 걸리는 SQL이 sqltiming 로그에 오류 수준으로 기록된다. 이 기능을 작동하게 하려면 sqltiming 로그를 활성화해야 한다. 그리고 로깅 레벨이 DEBUG로 활성화되어야 한다. | |
log4jdbc.dump.booleanastrueflase | SQL에서 boolean값을 dump할 때 true 또는 false로 dump한다. 설정하지 않으면 1 또는 0으로 dump된다. | false |
log4jdbc.dump.sql.maxlinelength | SQL을 dump할 때 한 번에 출력되는 행의 수를 제한할 수 있다. 0으로 설정하면 제한없이 출력된다. | 90 |
log4jdbc.dump.fulldebugstacktrace | DEBUG 모드에서 dump하는 경우 전체 stack trace를 dump한다. SQL에 대한 호출 체인을 추적할 때 유용할 수 있다. | false |
log4jdbc.dump.sql.select | SQL select문을 출력하지 않으려면 false로 설정한다. | true |
log4jdbc.dump.sql.insert | SQL insert문을 출력하지 않으려면 false로 설정한다. | true |
log4jdbc.dump.sql.update | SQL update문을 출력하지 않으려면 false로 설정한다. | true |
log4jdbc.dump.sql.delete | SQL delete문을 출력하지 않으려면 false로 설정한다. | true |
log4jdbc.dump.sql.create | SQL create문을 출력하지 않으려면 false로 설정한다. | true |
log4jdbc.dump.sql.addsemicolon | SQL 끝에 세미콜론을 추가하여 출력하고 싶을 때 true로 설정한다. 추후에 스크립트를 만들 때 유용할 수 있다. | false |
log4jdbc.spylogdelegator.name | 사용할 SpyLogDelegator의 정규화된 클래스 이름이다. log4jdbc-log4j2를 사용하려면 이 속성을 net.sf.log4jdbc.log.slf4j.Sl4jSpyLogDelegator로 설정해야 한다. 표준 log4jdbc 구현에는 없는 새로운 속성이다. | net.sf.log4jdbc.log.slf4j.Sl4jSpyLogDelegator |
log4jdbc.statement.warn | 명령문이 로그에서 사용될 때 로그에 경고를 표시하려면 true로 설정한다. | false |
log4jdbc.trim.sql | 로깅된 SQL을 트리밍하지 않으려면 false로 설정헌다. | true |
log4jdbc.trim.sql.extrablanklines | 로깅된 SQL에서 여분의 빈 줄을 트리밍하지 않으려면 false로 설정한다(기본적으로 한 행에 둘 이상의 빈 줄이 발생하면 연속된 줄은 하나의 빈 줄로 축소된다). | true |
log4jdbc.suppress.generated.keys.exception | Statement.getGeneratedKeys() 메서드에서 생성된 모든 예외를 무시하려면 true로 설정한다. | false |
4. 관련 설정 및 클래스 생성
❶ @MapperScan의 basePackageClasses 설정
@SpringBootApplication
@MapperScan(basePackageClasses = TestApplication.class)
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
❷ mapper 인터페이스 생성
@Mapper
public interface MemberMapper {
Optional<Member> findByEmail(String email);
}
❸ mapper.xml 생성
namespace에 매핑되는 mapper 클래스의 경로를 기입해야 한다. 그리고 아래와 같이 해당 쿼리문의 id를 위에 만든 인터페이스에 생성한 메서드 이름과 일치시킨다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.test.member.mapper.MemberMapper">
<select id="findByEmail" parameterType="String" resultType="com.test.member.domain.Member">
SELECT *
FROM member
WHERE email = #{email}
</select>
</mapper>
마무리
프로젝트에 어떤 설정이 필요하고 왜 필요한지를 충분히 고민한 후에 적용하는 것이 중요한 것 같다. 이번에도 서로 어떤 설정이 필요하고 왜 필요한가에 대해 이야기를 나누다 보니까 정말 필요한 선택들을 하게 됐고 결과적으로 깔끔하게 원하는 방향대로 설정할 수 있었다.
참고
'DB' 카테고리의 다른 글
[MySQL] com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure (0) | 2023.03.31 |
---|---|
[MySQL] SQL state [HY000]; error code [1366]; Incorrect string value (0) | 2023.03.31 |
[DB] JOIN 알고리즘과 성능에 대하여 (0) | 2023.03.15 |
[DB] JOIN의 종류 (0) | 2023.03.15 |
[DB] 인덱스(5) - 인덱스로 생성할 컬럼을 선택하는 기준 (0) | 2023.03.15 |