복붙노트

[SPRING] 동적 데이터 소스 라우팅

SPRING

동적 데이터 소스 라우팅

내 하찮은 영어 실력에 죄송하다는 말씀을 드리고 싶습니다. AbstractRoutingDataSource에 대한 구현을 작성했습니다.

public class DatabaseRoutingDataSource extends AbstractRoutingDataSource{

    @Override
    protected Object determineCurrentLookupKey() {      
        return DatabaseContextHolder.getDatabaseType();
    }

}

그리고 데이터베이스 간 전환을위한 새로운 클래스를 만들었습니다.

public class DatabaseContextHolder {

    private static final ThreadLocal<DatabaseType> contextHolder = new ThreadLocal<DatabaseType>();

    public static void setDatabaseType(DatabaseType databaseType) {
        contextHolder.set(databaseType);
    }

    public static DatabaseType getDatabaseType() {
        return (DatabaseType) contextHolder.get();
    }

    public static void clearDatabaseType() {
        contextHolder.remove();
    }
}

여기서 DatabaseType은 다음과 같습니다.

public enum DatabaseType {
    MAIN,
    BACKUP
}

내 beans.xml에서 :

<bean id="mainDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="java:/jdbc/DBMIDS"/>
</bean>
<bean id="backupDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="java:/jdbc/DBMIDS2"/>
</bean>
<bean id="dataSource" class="DatabaseRoutingDataSource">
    <property name="targetDataSources">
        <map key-type="DatabaseType">
            <entry key="MAIN" value-ref="mainDataSource"/>
            <entry key="BACKUP" value-ref="backupDataSource"/>
        </map>
    </property>
    <property name="defaultTargetDataSource" ref="mainDataSource"/>
</bean>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<bean id="databaseTarget" class="DatabaseBean">
    <property name="dataSource" ref="dataSource"/>
</bean>
<bean id="database" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager" ref="transactionManager"/>
    <property name="target" ref="databaseTarget"/>
    <property name="proxyInterfaces">
        <value>Database</value>
    </property>
    <property name="transactionAttributes">
        <props>
            <prop key="*">PROPAGATION_REQUIRED,-MyException</prop>
        </props>
    </property>
</bean>

자, DAO에서 데이터 소스를 변경하려고 할 때 :

public class DatabaseBean extends JdbcDaoSupport implements Database
    public void myMethod() {
       DatabaseContextHolder.setDatabaseType(DatabaseType.MAIN);
       getJdbcTemplate().execute("INSERT INTO test(test) VALUES('test')");      
       DatabaseContextHolder.setDatabaseType(DatabaseType.BACKUP);
       getJdbcTemplate().execute("INSERT INTO test(test) VALUES('test')");        
}

첫 번째 실행 getJdbcTemplate () 및 datasource가 전환되지 않으면 onceCurrentLookupKey ()가 호출됩니다.

해결법

  1. ==============================

    1.JDBC 트랜잭션의 Spring 트랜잭션 관리 부분은 트랜잭션 시작시 연결을 스레드에 바인드하는 것입니다. 트랜잭션이 종료되고 연결이 언 바운드 될 때까지 동일한 데이터 소스의 모든 지속성 작업은 동일한 연결을 사용합니다. 단일 데이터 소스를 사용하여 두 개의 다른 데이터 소스를 마스킹하기 때문에 하나의 연결 만 가져옵니다. 명시 적으로 두 개의 별도 데이터 소스를 사용했다면 각각은 별도의 리소스로 간주되어 별도의 연결이 시작되어 각각에 대한 스레드에 바인딩됩니다. JdbcDaoSupport 및 JdbcTemplate을 사용하여 트랜잭션을 사용할 때의 실제 상황에 대한 힌트를 얻으려면 참조 가이드의 "트랜잭션과 리소스 동기화"를 참조하십시오.

    JDBC 트랜잭션의 Spring 트랜잭션 관리 부분은 트랜잭션 시작시 연결을 스레드에 바인드하는 것입니다. 트랜잭션이 종료되고 연결이 언 바운드 될 때까지 동일한 데이터 소스의 모든 지속성 작업은 동일한 연결을 사용합니다. 단일 데이터 소스를 사용하여 두 개의 다른 데이터 소스를 마스킹하기 때문에 하나의 연결 만 가져옵니다. 명시 적으로 두 개의 별도 데이터 소스를 사용했다면 각각은 별도의 리소스로 간주되어 별도의 연결이 시작되어 각각에 대한 스레드에 바인딩됩니다. JdbcDaoSupport 및 JdbcTemplate을 사용하여 트랜잭션을 사용할 때의 실제 상황에 대한 힌트를 얻으려면 참조 가이드의 "트랜잭션과 리소스 동기화"를 참조하십시오.

  2. ==============================

    2.메서드 호출 전에 DatabaseContextHolder.setDatabaseType (DatabaseType.MAIN)을 호출해야합니다. Hibernate는 트랜잭션이 시작되면 커넥션을 찾는다. 귀하의 경우 DatabaseContextHolder.setDatabaseType (DatabaseType.MAIN)이 실행되기 전에 트랜잭션이 시작됩니다. 트랜잭션이 시작되면 스키마를 변경할 수 없습니다. 구현은 메소드 호출 전에, 즉 트랜잭션이 시작되기 전에 DatabaseType을 올바르게 설정해보십시오.

    메서드 호출 전에 DatabaseContextHolder.setDatabaseType (DatabaseType.MAIN)을 호출해야합니다. Hibernate는 트랜잭션이 시작되면 커넥션을 찾는다. 귀하의 경우 DatabaseContextHolder.setDatabaseType (DatabaseType.MAIN)이 실행되기 전에 트랜잭션이 시작됩니다. 트랜잭션이 시작되면 스키마를 변경할 수 없습니다. 구현은 메소드 호출 전에, 즉 트랜잭션이 시작되기 전에 DatabaseType을 올바르게 설정해보십시오.

  3. from https://stackoverflow.com/questions/7304019/dynamic-datasource-routing by cc-by-sa and MIT license