2011-09-11 5 views
3

데이터베이스 스키마간에 동적으로 전환해야하는 Spring + Hibernate/Flex 애플리케이션이 있습니다. 이를 달성하기 위해 this 기사 다음에 AbstractRoutingDataSource를 구현했습니다. 불행히도 그것은 작동하지 않습니다. 실제로는 기본 스키마 (logical_public)에서 SQL을 실행합니다. 어떤 도움이라도 대단히 감사하겠습니다. 감사.는 두 개의 데이터 소스를 포함Spring + Hibernate SessionFactory + AbstractRoutingDataSource

applicationContext.xml :

여기 내 설정이다. 각 데이터 소스는 다른 로그인 역할로 데이터베이스에 연결됩니다. 라우팅 데이터 소스는 String 키를 사용하여 올바른 데이터 소스를 선택합니다. SchemaConstants 클래스는 public static final 필드를 포함합니다.

<bean id="parentDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> 
    <property name="driverClass" value="org.postgresql.Driver"/> 
    <property name="jdbcUrl" value="jdbc:postgresql://localhost:5432/mystore"/> 
    <property name="acquireIncrement" value="3"/> 
    <property name="minPoolSize" value="1"/> 
    <property name="maxPoolSize" value="15"/> 
    <property name="maxStatementsPerConnection" value="100"/> 
    <property name="automaticTestTable" value="c3p0_test_table"/> 
    <property name="numHelperThreads" value = "20"/> 
</bean> 

<bean id="publicDS" parent="parentDataSource"> 
    <property name="user" value="postgres"/> 
    <property name="password" value="password"/> 
</bean> 

<bean id="tempSchemaDS" parent="parentDataSource"> 
    <property name="user" value="temp_role"/> 
    <property name="password" value="tmppsw"/> 
</bean> 

<bean id="routingDS" class="flex.RoutingDataSource"> 
    <property name="targetDataSources"> 
     <map key-type="java.lang.String"> 
     <entry key="flex.SchemaConstants.LOGICAL_PUBLIC" value-ref="publicDS"/> 
     <entry key="flex.SchemaConstants.TEMP_SCHEMA" value-ref="tempSchemaDS"/> 
     </map> 
    </property> 
    <property name="defaultTargetDataSource" ref="publicDS"/> 
</bean> 

RoutingDataSource 구현 : 많은 아무것도 여기에 추가 없습니다.

public class RoutingDataSource extends AbstractRoutingDataSource 
{ 
    @Override 
    protected Object determineCurrentLookupKey() 
    { 
     return Globals.getSchema(); 
    } 

    @Override 
    public Logger getParentLogger() throws SQLFeatureNotSupportedException 
    { 
     // TODO Auto-generated method stub 
     return null; 
    } 
} 

전역 클래스 : 저장하고 데이터 소스 키를 조회하는 데 사용됩니다.

public class Globals 
{ 
    private static final ThreadLocal<String> schemaHolder 
     = new ThreadLocal<String>(); 

    public static void setSchema(String schema) 
    { 
     schemaHolder.set(schema); 
    } 

    public static String getSchema() 
    { 
     return schemaHolder.get(); 
    } 

    public static void clearCustomerType() 
    { 
     schemaHolder.remove(); 
    } 
} 

테스트 코드 : 기록의 몇 가지를 삽입하려고합니다, 다른 스키마 (그리고 다른 테이블)의 각

@RemotingInclude 
@Transactional 
public void test() 
{ 
    Globals.setSchema(SchemaConstants.TEMP_SCHEMA); 

    SomeDataOther someOtherData = new SomeDataOther(); 
    someOtherData.setName("Jorjinio"); 
    this.sessionFactory.getCurrentSession().save(someOtherData); 


    Globals.setSchema(SchemaConstants.LOGICAL_PUBLIC); 

    SomeData someData = new SomeData(); 
    someData.setFirstName("Hulio"); 
    someData.setLastName("Julio"); 
    this.sessionFactory.getCurrentSession().save(someData); 
} 

보조 질문입니다. 이러한 상황에서 데이터 무결성을 유지하는 올바른 방법은 무엇입니까? 나는 @Transactional 속성으로 메소드에 주석을 달았지만 너무 쉽게 작동 할 것이라고 확신하지 못했습니다. 내가 사용하고있는 transactionManager는 org.springframework.orm.hibernate3.HibernateTransactionManager 타입이다. 나는이 문제에 관해 아직 연구하지 않았지만 누군가가 정보를 제공 할 수 있다면 크게 환영받을 것이다.

+0

그래서 JTA 트랜잭션이 두 저장을 캡슐화하도록 관리 했습니까? 방법? – Vedran

답변

7

이 거래 바인딩 최대 절전 모드 Session 만들 때 특정 DataSource의 선택은 실제로 즉, AbstractRoutingDataSource.getConnection()가 호출 될 때 발생하는 것이 분명하다. 귀하의 경우에는 @Transactional 방법을 입력하면됩니다.

따라서 트랜잭션 내에서 스키마를 전환 할 수 없습니다. 서로 다른 스키마에 대해 별도의 트랜잭션을 실행해야합니다. 동일한 메서드 내에서 여러 트랜잭션을 실행하려면 @Transactional 대신 프로그래밍 방식의 트랜잭션 관리 (TransactionTemplate)를 사용할 수 있습니다.