【问题标题】:Spring + Hibernate SessionFactory + AbstractRoutingDataSourceSpring + Hibernate SessionFactory + AbstractRoutingDataSource
【发布时间】:2011-09-11 14:30:09
【问题描述】:

我有一个需要在数据库模式之间动态切换的 Spring+Hibernate/Flex 应用程序。为了实现这一点,我在this 文章之后实现了一个 AbstractRoutingDataSource。不幸的是,它不起作用。它实际上在默认模式(logical_public)中执行 SQL。任何帮助将不胜感激。谢谢。

这是我的设置:

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

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 属性注释了该方法,但我不确定这是否会如此容易。我使用的 transactionManager 是 org.springframework.orm.hibernate3.HibernateTransactionManager 类型。我还没有对此事进行任何研究,但如果有人能提供信息,我将不胜感激。

【问题讨论】:

  • 那么您是否设法让 JTA 事务封装了两个保存?怎么样?

标签: hibernate spring


【解决方案1】:

很明显,特定DataSource 的选择实际上发生在调用AbstractRoutingDataSource.getConnection() 时,即在创建事务绑定Hibernate Session 时。在您的情况下,当您输入 @Transactional 方法时会发生这种情况。

因此,您不能在事务中切换方案。您必须针对不同的方案执行单独的事务。要在同一方法中执行多个事务,您可以使用编程事务管理 (TransactionTemplate) 而不是 @Transactional

【讨论】:

    猜你喜欢
    • 2011-12-28
    • 1970-01-01
    • 2011-05-06
    • 2012-06-10
    • 2015-12-31
    • 2018-03-22
    • 2014-09-23
    • 2015-06-10
    • 1970-01-01
    相关资源
    最近更新 更多