View Full Version : Multiple datasources and SessionFactories
pathakn
01-06-2007, 07:15 PM
Hi Mark
I have a requirement to import some of the information from one datasource to other. I have created two different sessionfactories in my xml config file and both have their respective dataproviders, transaction interceptors etc.
How is thread local pattern supposed to work when I have multiple sessionfactories each trying to connect to different databases?
Also, I have a situation where the TransactionSynchronizerManager throws an error and complains that the sessionfactory is already bound. Is this because it just takes the fully qualified name of the sessionfactory?
Is this correct? What are my alternatives?
Mark Pollack
01-06-2007, 08:12 PM
Hi Nilesh,
The design places the actual SessionFactory instance as the key in a hashtable and the hashtable itself is stored in thread local storage using the key "Spring.Transactions:resources". So there should not be any issue using multiple session factories from this perspective. I've used multiple DbProviders with AdoTemplate on a few projects successfully. Can you turn on debug level logging and post it. I will recreate your scenaro to reproduce the issue. Are you using TxScopeTransactionManager so that both operations are done with in an distributed transaction?
Mark
Mark Pollack
01-07-2007, 05:14 AM
Hi,
I created a working example that uses multiple databases. It is located in the Sping.NHibernate 1.0.2 project and is named MultipleDbTests.cs. You can get the latest download. I've added the config file here since most likely there is some error in your configuration.
Cheers,
Mark
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns='http://www.springframework.net'
xmlns:db="http://www.springframework.net/database">
<db:dbProvider id="DbProvider1"
provider="SqlServer-1.1"
connectionString="Data Source=(local);Database=Spring;User ID=springqa;Password=springqa;Trusted_Connection=F alse"/>
<db:dbProvider id="DbProvider2"
provider="SqlServer-1.1"
connectionString="Data Source=(local);Database=Spring2;User ID=springqa2;Password=springqa2;Trusted_Connection =False"/>
<object id="SessionFactory1" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate">
<property name="DbProvider" ref="DbProvider1"/>
<property name="MappingAssemblies">
<list>
<value>Spring.Data.NHibernate.Integration.Tests</value>
</list>
</property>
<property name="HibernateProperties">
<dictionary>
<entry key="hibernate.connection.provider"
value="NHibernate.Connection.DriverConnectionProvider"/>
<entry key="hibernate.dialect"
value="NHibernate.Dialect.MsSql2000Dialect"/>
<entry key="hibernate.connection.driver_class"
value="NHibernate.Driver.SqlClientDriver"/>
</dictionary>
</property>
</object>
<object id="SessionFactory2" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate">
<property name="DbProvider" ref="DbProvider2"/>
<property name="MappingAssemblies">
<list>
<value>Spring.Data.NHibernate.Integration.Tests</value>
</list>
</property>
<property name="HibernateProperties">
<dictionary>
<entry key="hibernate.connection.provider"
value="NHibernate.Connection.DriverConnectionProvider"/>
<entry key="hibernate.dialect"
value="NHibernate.Dialect.MsSql2000Dialect"/>
<entry key="hibernate.connection.driver_class"
value="NHibernate.Driver.SqlClientDriver"/>
</dictionary>
</property>
</object>
<object id="transactionManager"
type="Spring.Data.TxScopeTransactionManager, Spring.Data">
</object>
<object id="AccountCreditDao" type="Spring.Data.NHibernate.AccountCreditDao, Spring.Data.NHibernate.Integration.Tests">
<property name="SessionFactory" ref="SessionFactory1"/>
</object>
<object id="AccountDebitDao" type="Spring.Data.NHibernate.AccountDebitDao, Spring.Data.NHibernate.Integration.Tests">
<property name="SessionFactory" ref="SessionFactory2"/>
</object>
<!-- The DAO object that performs multiple data access operations -->
<object id="accountManagerTarget"
type="Spring.Data.NHibernate.AccountManager, Spring.Data.NHibernate.Integration.Tests">
<property name="AccountCreditDao" ref="AccountCreditDao"/>
<property name="AccountDebitDao" ref="AccountDebitDao"/>
</object>
<!-- Transactional Proxy for TestObjectManager using the ProxyFactoryObject -->
<object id="accountManager"
type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
<property name="Target" ref="accountManagerTarget"/>
<property name="InterceptorNames">
<value>transactionInterceptor</value>
</property>
</object>
<!-- Transaction Interceptor based on attribute [Transaction()] -->
<object id="transactionInterceptor"
type="Spring.Transaction.Interceptor.TransactionIntercep tor, Spring.Data">
<property name="TransactionManager" ref="transactionManager"/>
<!-- note do not have converter from string to this property type registered -->
<property name="TransactionAttributeSource">
<object type="Spring.Transaction.Interceptor.AttributesTransacti onAttributeSource, Spring.Data"/>
</property>
</object>
</objects>
pathakn
01-07-2007, 04:05 PM
I had a quick look at the MultiDbTests.xml.
I have defined two different transaction managers (HibernateTransactionManager) and interceptors one each for my datasources in my configuration as the import happens from UI layer not service layer. Is that a good desighn choice? In the hindsight I think no.
I get a list of domain object (imported) from one service method and then export it using another service method.
Also I am using ObjectNameAutoProxyCreator instead of ProxyFactoryObject for AOP. Will the TxScopeTransactionManager work in this case? What would be the configuration like. I don't see any thing similar in examples.
I can probably change my presentation logic and move it to service layer.
Mark Pollack
01-08-2007, 02:43 AM
Hi,
Generally speaking design wise I would recomend that the UI layer be as "thin" as possible, delegating business actions to a controller and the controller in turn would delegate to a business service, which in turn coordinates data access objects. However, every app doesn't need to go "full out" like this, if you are just doing simple import/export two tier app, the GUI could call the service(s) directly, but it has to be very simple app otherwise this approach will break down in terms of organizing a large codebase.
There is no problem using ObjectNameAutoProxyCreator as compared to ProxyFactoryObject in your case. In fact, ObjectNameAutoProxyCreator is a better choice generally speaking. I just happened to use ProxyFactoryObject. TxScopeTransactionManger will work just fine with ObjectNameAutoProxyCreator. If you want the semantics of having both db operations within the same distributed transaction, you should use TxScopeTransactionManager.
If for some reason you do not want to use TxScopeTransactionManager, you will nee to create two 'parallel" configurations. You need two ObjectNameAutoProxyCreators and two TransactionInterceptors. Each TransactionInterceptor will reference a different AdoTransactionManager which in turn references a different DbProvider.
The one thing to keep in mind in this the case of using two AdoTransactionManagers is that you should not use AttributesTransactionAttributeSource, i.e. transactions that are driven based on the [Transaction()] attribute. This is because all that implemetation of ITransactionAttributeSource knows is about the presence of the attribute and nothing more - not which database it is associated with nor a filter to limit the pointcut to only certain classes. Additional class filtering might be a nice addition... In anycase, you need to associate one transaction manager for some of the methods (those dealing with reading form the source database) and a different one for methods dealing with the target database. To do this I suggest using MethodMapTransactionAttributeSource which will allow you to specify the fully qualified name of the class + method name and its associated transaction properties. See the reference docs, here (http://www.springframework.net/doc-latest/reference/html/transaction.html#d0e8611), for an example.
If you want all-or-nothing transaciton semantics in doing the transfer from one db to another, and can live with the performance of using distributed transactions, I would go with TxScopeTransactionManager. However, performance maybe a concern so experiment and see which tradeoffs you can live with - easier configuration as compared to decreased performance but all-or-nothing semantics.
Cheers,
Mark
vBulletin® v3.7.3, Copyright ©2000-2009, Jelsoft Enterprises Ltd.