Spring + Hibernate SessionFactory + AbstractRoutingDataSource - PullRequest
3 голосов
/ 11 сентября 2011

У меня есть приложение Spring + Hibernate / Flex, которое должно динамически переключаться между схемами базы данных. Чтобы добиться этого, я реализовал AbstractRoutingDataSource после этой статьи. К сожалению, это не работает. Он фактически выполняет SQL в схеме по умолчанию (logic_public). Любая помощь будет принята с благодарностью. Спасибо.

Вот мои настройки:

applicationContext.xml содержит два источника данных. Каждый источник данных подключается к базе данных с различной ролью входа. Источник данных маршрутизации выбирает правильный источник данных, используя ключ String. Класс SchemaConstants содержит пару открытых статических полей 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;
    }
}

Класс Globals: Используется для хранения и поиска ключа источника данных.

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 , но я далеко не уверен, что это будет работать так легко. Менеджер транзакций, который я использую, имеет тип org.springframework.orm.hibernate3.HibernateTransactionManager. Я еще ничего не исследовал по этому вопросу, но если кто-то сможет предоставить информацию, она также будет очень признательна.

1 Ответ

8 голосов
/ 11 сентября 2011

Понятно, что выбор конкретного DataSource действительно происходит при вызове AbstractRoutingDataSource.getConnection(), то есть при создании привязанного к транзакции Hibernate Session.В вашем случае это происходит, когда вы вводите метод @Transactional.

Таким образом, вы не можете переключать схемы внутри транзакции.Вы должны выполнить отдельные транзакции против разных схем.Для выполнения нескольких транзакций внутри одного и того же метода вы можете использовать программное управление транзакциями (TransactionTemplate) вместо @Transactional.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...