Spring + Hibernate SessionFactory + AbstractRoutingDataSource [英] Spring + Hibernate SessionFactory + AbstractRoutingDataSource

查看:147
本文介绍了Spring + Hibernate SessionFactory + AbstractRoutingDataSource的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



这是我的设置:
$ b applicationContext.xml 包含两个数据源。每个数据源使用不同的登录角色连接到数据库。路由数据源通过使用String键选择正确的数据源。 SchemaConstants类包含几个 public static final 字段。

 < bean id =parentDataSource class =com.mchange.v2.c3p0.ComboPooledDataSourcedestroy-method =close> 
< property name =driverClassvalue =org.postgresql.Driver/>
< property name =jdbcUrlvalue =jdbc:postgresql:// localhost:5432 / mystore/>
< property name =acquireIncrementvalue =3/>
< property name =minPoolSizevalue =1/>
< property name =maxPoolSizevalue =15/>
< property name =maxStatementsPerConnectionvalue =100/>
< property name =automaticTestTablevalue =c3p0_test_table/>
< property name =numHelperThreadsvalue =20/>
< / bean>

< bean id =publicDSparent =parentDataSource>
< property name =uservalue =postgres/>
< property name =passwordvalue =password/>
< / bean>

< bean id =tempSchemaDSparent =parentDataSource>
< property name =uservalue =temp_role/>
< property name =passwordvalue =tmppsw/>
< / bean>

< bean id =routingDSclass =flex.RoutingDataSource>
< property name =targetDataSources>
< map key-type =java.lang.String>
< entry key =flex.SchemaConstants.LOGICAL_PUBLICvalue-ref =publicDS/>
< entry key =flex.SchemaConstants.TEMP_SCHEMAvalue-ref =tempSchemaDS/>
< / map>
< / property>
< property name =defaultTargetDataSourceref =publicDS/>
< / bean>

RoutingDataSource实施:这里没有多少内容。

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

$ b @Override
public Logger getParentLogger()抛出SQLFeatureNotSupportedException
{
// TODO自动生成的方法存根
返回null;


Globals类:用于存储和查找数据源键。

  public class Globals 
{
private static final ThreadLocal<串GT; 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。我还没有研究任何事情,但如果有人可以提供信息,它将不胜感激。

清楚的是,当调用 AbstractRoutingDataSource.getConnection()时,实际上发生了对特定 DataSource 的选择,即当事务绑定Hibernate 会话已创建。在你的情况下,当你输入一个 @Transactional 方法时会发生这种情况。



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


I have an Spring+Hibernate/Flex application that needs to switch dynamically between database schemas. To accomplish that I implemented a AbstractRoutingDataSource following this article. Unfortunately it doesn't work. It actually executes the SQL in the default schema(logical_public). Any help would be greatly appreciated. Thanks.

Here's my setup:

applicationContext.xml contains the two datasources. Each datasource connects to the database with a different login role. The routing datasource picks the right datasource by using a String key. The SchemaConstants class contains a couple of public static final fields.

<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 implementation: Nothing much to add here.

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

The Globals class: Used to store and lookup the datasource key.

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

Test code: Tries to insert a couple of records, each in different schema(and different tables)

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

A secondary question. What is the correct way to do keep my data integrity in such a situation? I have annotated the method with @Transactional attribute but I'm far from certain that this would work so easily. The transactionManager I am using is of type org.springframework.orm.hibernate3.HibernateTransactionManager. I haven't yet research anything on the matter but if someone can provide information it will be greatly appreciated as well.

解决方案

It's clear that selection of a particular DataSource actually happens when AbstractRoutingDataSource.getConnection() is called, i.e. when transaction-bound Hibernate Session is created. In your case it happens when you enter a @Transactional method.

Thus, you can't switch schemes inside a transaction. You have to execute separate transactions against different schemes. To execute several transactions inside the same method you can use programmatic transaction management (TransactionTemplate) instead of @Transactional.

这篇关于Spring + Hibernate SessionFactory + AbstractRoutingDataSource的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆