我有一个Spring + Hibernate / Flex应用程序,需要在数据库模式之间动态切换。为了实现这个目标我实现了一个AbstractRoutingDataSource下面这个文章。不幸的是,它不起作用。它实际上以默认架构(logical_public)执行SQL。任何帮助将不胜感激。谢谢。
这是我的设置:
applicationContext.xml 包含两个数据源。每个数据源都以不同的登录角色连接到数据库。路由数据源通过使用String键选择正确的数据源。SchemaConstants类包含几个 公共的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。我尚未对此事进行任何研究,但如果有人可以提供信息,也将不胜感激。
显然,对特定对象的选择DataSource实际上AbstractRoutingDataSource.getConnection()是在调用时发生的,即在Session创建受事务绑定的Hibernate时。在您的情况下,当您输入@Transactional方法时会发生这种情况。
DataSource
AbstractRoutingDataSource.getConnection()
Session
@Transactional
因此,您不能在事务内部切换方案。您必须针对不同的方案执行单独的事务。要以相同的方法执行多个事务,可以使用程序化事务管理(TransactionTemplate)代替@Transactional。
TransactionTemplate