MySQL JDBC
PreparedStatement 분석
addBatch
rewriteBatchedStatements=true&useServerPrepStmts=false
: addBatch 구문을 INSERT INTO tablename values (), (), …
' 형태로 변경한다.
rewriteBatchedStatements=true
상황에서 addBatch 적정 레코드 수는 (12 * 1024) / 평균레코드크기
로 구한다.즉, 누적 데이터가12kb일 때 최고 성능을 발휘한다고 한다.
fetchSize
MySQL Connector/J에서 Statement.setFetchSize(int)
는 정상작동하지 않는다.
기본적으로 모든 쿼리 결과 데이터를 한꺼번에 전송받아 메모리에 올린 상태로 ResultSet
에 접근한다.
이를 서버 커서 방식으로 바꾸려면 JDBC URL에 useCursorFetch=true?defaultFetchSize=100
형태로 옵션을 추가해야 한다.
Datetime 0
0000-00-00 00:00:00
인 날짜가 존재할 경우 JDBC 드라이버 입장에서는 말도 안되는 시간이다. 따라서 오류가 발생한다.
zeroDateTimeBehavior=convertToNull
를 JDBC URL에 추가해주면 이 시간을 null로 간주한다.
그냥 오류를 발생시키고 잘못된 데이터를 보정하는 것이 맞을 것 같다.
zeroDateTimeBehavior
What should happen when the driver encounters DATETIME values
that are composed entirely of zeros (used by MySQL to represent invalid dates)?
Valid values are "exception", "round" and "convertToNull".
Default: exception
Replication JDBC Driver
-
Connection.setReadOnly()에 지정된 값에 따라 쓰기일 때는 마스터, 그 외에는 슬레이브로 보내는 처리를 해준다. Spring @Transactional(readOnly=“true|false”)
com.mysql.jdbc.ReplicationDriver
JDBC 드라이버 사용
Connector/J 5.0.6 버전에서는 그냥 기본 드라이버로 설정해도 된다. 기본 드라이버가 커넥션 요청이 들어올 때 Replication
URL 이면 자동으로 리플리케이션 드라이버에게 위임한다.
JDBC
URL :
jdbc:mysql:replication://master,slave1,slave2,slave3/test
roundRobinLoadBalance=true
: 슬레이브들 간에 Load Balancing 파라미터
autoReconnect=true
: 커넥션 끊겼을 때 자동 재접속
autoReconnectForPools=true
failOverReadOnly=true
To enable this functionality, use the com.mysql.jdbc.ReplicationDriver class when configuring your application server's connection pool or when creating an instance of a JDBC driver for your standalone application. Because it accepts the same
URL format as the standard MySQL JDBC driver, ReplicationDriver does not currently work with java.sql.DriverManager-based connection creation unless it is the only MySQL JDBC driver registered with the DriverManager.
Ping용 쿼리를 주로
SELECT 1
을 사용하는데 ReplicationDriver 사용시에는 문제가 된다. 항상 Master/Slave 두개의 커넥션을 유지하는데 이 경우에는 한쪽으로만 쿼리가 실행되기 때문에다.
/* ping */ SELECT 1
이라고 해야 JDBC의
ping()
함수를 모든 커넥션에 실행한다.
MySQL Bug #22643
java.sql.SQLException: No database selected
에러가 발생한다면, JDBC URL에 database를 지정하지 않았기 때문이다. MySQL 기본 드라이버는 DB를 지정하지 않고 쿼리에서 DB명을 명시해도 괜찮지만 replication 드라이버는 이 경우 오류를 냄.
-
Sharding
MySQL JDBC Properties
connection/socket timeout
-
SocketTimeout이나 ConnectTimeout을 설정하지 않으면 네트워크 장애가 발생해도 애플리케이션이 대부분 이를 감지할 수 없다. 따라서 연결이 되거나 데이터를 읽을 수 있을 때까지 애플리케이션이 무한정 기다리게 된다. –> 따라서 꼭 socketTimeout을 지정하자.
-
connectTimeout
: Connection timeout in milliseconds. 소켓 연결을 맺기까지의 timeout.
socketTimeout
: Socket Operation timeout in milliseconds. server → client 전송 timeout.
JDBC Query Log
MySQL이 생성하는 모든 쿼리의 로그를 남길 수 있다.
logger=com.mysql.jdbc.log.Slf4JLogger
: 로거 지정
profileSQL=true
이면 로그로 모든 쿼리를 남기고 성능 지표도 함께 표시한다.
Interceptor
JDBC 드라이버를 통해 각 라이프사이클별 인터셉터를 끼워넣을 수 있다.
-
connectionLifecycleInterceptors
, where you specify the fully qualified names of classes that implement the com.mysql.jdbc.ConnectionLifecycleInterceptor interface. In these kinds of interceptor classes, you might log events such as rollbacks, measure the time between transaction start and end, or count events such as calls to setAutoCommit().
exceptionInterceptors
, where you specify the fully qualified names of classes that implement the com.mysql.jdbc.ExceptionInterceptor interface. In these kinds of interceptor classes, you might add extra diagnostic information to exceptions that can have multiple causes or indicate a problem with server settings. Because exceptionInterceptors classes are only called when handling a SQLException thrown from Connector/J code, they can be used even in production deployments without substantial performance overhead.
statementInterceptors
, where you specify the fully qualified names of classes that implement the com.mysql.jdbc.StatementInterceptorV2 interface. In these kinds of interceptor classes, you might change or augment the processing done by certain kinds of statements, such as automatically checking for queried data in a memcached server, rewriting slow queries, logging information about statement execution, or route requests to remote servers.
JDBC Driver 버전 정보 확인
// 이 코드의 클래스는 package가 com.mysql.jdbc
// Mockito.mock 사용
DatabaseMetaData metaData = new DatabaseMetaData(mock(MySQLConnection.class), null);
log.info("Version : {}, {}", metaData.getDriverName(), metaData.getDriverVersion());
com.mysql.jdbc.Driver
클래스에도 getMajorVersion()
, getMinorVersion()
메소드가 있지만 마지막 subMinorVersion
을 알 수 있는 방법은 없다.
Ping Validation
-
쿼리가 /* ping */
으로 시작하면 MYSQL JDBC 드라이버는 이 쿼리를 실제로 날리지 않고, MySQL 서버에 살아있는지 여부만 체크하는 통신을 수행한다. Statement
, PreparedStatement
상관없이 작동한다.
공백하나 다른 것 없이 정확히 /* ping */
와 완전히 동일한 문자열로 시작하는 쿼리여야 한다.
ReplicationConnection
이나 LoadBalancedConnection
사용시에는 연결된 모든 커넥션이 ping을 실행한다.
-
댓글 없음:
댓글 쓰기