2011-09-11 4 views
3

J'ai une application Spring + Hibernate/Flex qui doit basculer dynamiquement entre les schémas de base de données. Pour ce faire, j'ai implémenté un article AbstractRoutingDataSource suivant this. Malheureusement, cela ne fonctionne pas. Il exécute en fait le SQL dans le schéma par défaut (logical_public). Toute aide serait grandement appréciée. Merci.Spring + Hibernate SessionFactory + AbstractRoutingDataSource

Voici ma configuration:

applicationContext.xml contient les deux sources de données. Chaque source de données se connecte à la base de données avec un rôle de connexion différent. La source de données de routage sélectionne la bonne source de données en utilisant une clé String. La classe SchemaConstants contient deux champs publics statiques finals.

<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> 

mise en œuvre de RoutingDataSource: Pas grand-chose à ajouter ici.

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; 
    } 
} 

La classe Globals: Utilisé pour stocker et rechercher la clé de source de données.

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(); 
    } 
} 

Code d'essai: tente d'insérer quelques enregistrements, chacun dans différents schémas (et tables différentes)

@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); 
} 

Une question secondaire. Quelle est la bonne façon de garder mon intégrité des données dans une telle situation? J'ai annoté la méthode avec l'attribut @Transactional mais je suis loin d'être certain que cela fonctionnerait si facilement. Le gestionnaire de transaction que j'utilise est de type org.springframework.orm.hibernate3.HibernateTransactionManager. Je n'ai pas encore fait de recherches sur le sujet, mais si quelqu'un peut fournir des informations, cela sera grandement apprécié.

+0

Alors avez-vous réussi à faire encapsuler une transaction JTA à la fois les sauvegardes? Comment? – Vedran

Répondre

7

Il est clair que la sélection d'un DataSource particulier se produit réellement lorsque AbstractRoutingDataSource.getConnection() est appelée, c'est-à-dire lorsque Hibernate Session lié à une transaction est créé. Dans votre cas, cela se produit lorsque vous entrez une méthode @Transactional. Par conséquent, vous ne pouvez pas changer de modèle à l'intérieur d'une transaction. Vous devez exécuter des transactions distinctes sur différents schémas. Pour exécuter plusieurs transactions dans la même méthode, vous pouvez utiliser la gestion des transactions par programme (TransactionTemplate) au lieu de @Transactional.

Questions connexes