Created
July 21, 2013 08:26
-
-
Save debop/6047921 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kr.hconnect.data.jpa.mysql; | |
import lombok.Getter; | |
import org.aspectj.lang.ProceedingJoinPoint; | |
import org.aspectj.lang.annotation.Around; | |
import org.aspectj.lang.annotation.Aspect; | |
import org.hibernate.Session; | |
import org.hibernate.jdbc.Work; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import org.springframework.stereotype.Component; | |
import org.springframework.transaction.annotation.Transactional; | |
import javax.persistence.EntityManager; | |
import javax.persistence.PersistenceContext; | |
import java.sql.Connection; | |
import java.sql.SQLException; | |
/** | |
* MySQL Replication 환경 (Master-Slave)에서 | |
* {@link org.springframework.transaction.annotation.Transactional#readOnly()} 이 true로 정의된 Method에 대해서는 | |
* Slave 서버로 접속하기 위해, {@link java.sql.Connection#isReadOnly()}의 속성을 true로 변경하여 작업을 수행하도록 합니다. | |
* | |
* @author 배성혁 [email protected] | |
* @since 13. 7. 21. 오후 3:20 | |
*/ | |
@Aspect | |
@Component | |
public class MySqlConnectionInterceptor { | |
private static final Logger log = LoggerFactory.getLogger(MySqlConnectionInterceptor.class); | |
private static final boolean isTraceEnabled = log.isTraceEnabled(); | |
@PersistenceContext | |
EntityManager em; | |
/** `@Transactional` 이 있는 메소드를 intercept 해서 readOnly 값에 따라 MySQL의 Master / Slave 서버를 구분합니다. */ | |
@Around(value = "@annotation(transactional) if transactional.readOnly()", argNames = "pjp, transactional") | |
public Object proceed(final ProceedingJoinPoint pjp, final Transactional transactional) throws Throwable { | |
if (log.isTraceEnabled()) | |
log.trace("읽기전용 작업을 수행하기 위해 현 connection를 readonly로 설정합니다..."); | |
Session session = em.unwrap(Session.class); | |
ConnectionReadOnlyWork readOnlyWork = new ConnectionReadOnlyWork(); | |
try { | |
session.doWork(readOnlyWork); | |
return pjp.proceed(); | |
} finally { | |
session.doWork(new RestoreConnectionWork(readOnlyWork)); | |
} | |
} | |
static class ConnectionReadOnlyWork implements Work { | |
@Getter boolean autoCommit; | |
@Getter boolean readOnly; | |
@Override | |
public void execute(Connection connection) throws SQLException { | |
this.autoCommit = connection.getAutoCommit(); | |
this.readOnly = connection.isReadOnly(); | |
connection.setAutoCommit(false); | |
connection.setReadOnly(true); | |
} | |
} | |
static class RestoreConnectionWork implements Work { | |
@Getter boolean autoCommit; | |
@Getter boolean readOnly; | |
public RestoreConnectionWork(ConnectionReadOnlyWork readOnlyWork) { | |
this.autoCommit = readOnlyWork.isAutoCommit(); | |
this.readOnly = readOnlyWork.isReadOnly(); | |
} | |
@Override | |
public void execute(Connection connection) throws SQLException { | |
connection.setAutoCommit(autoCommit); | |
connection.setReadOnly(readOnly); | |
if (log.isTraceEnabled()) | |
log.trace("읽기전용 작업을 수행하고, connection의 원래 설정으로 재설정했습니다."); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment