2011-09-11 16 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

具体的なDataSourceの選択は、AbstractRoutingDataSource.getConnection()が呼び出されたとき、つまりトランザクションにバインドされたHibernate Sessionが作成されたときに実際に発生することは明らかです。あなたの場合は、@Transactionalメソッドを入力すると起こります。

したがって、トランザクション内でスキームを切り替えることはできません。異なるスキームに対して別々のトランザクションを実行する必要があります。同じメソッド内で複数のトランザクションを実行するには、@Transactionalの代わりにプログラムによるトランザクション管理(TransactionTemplate)を使用できます。

関連する問題