0
votes

I am using Spring Batch to import large set of data from XML to Oracle database.

My application is multi tenant aware where each tenant can have separate db schema or few tenants can also share single db schema at the same time.

From my XML, I am getting unique tenant identifier which I used as a tenant database resolution identifier to select DB at a runtime.

I am using Spring MVC, hibernate.

My XML

<users>
 <user>
    <userAccountDetail>
        <tenantId>acmebank</tenantId>
        <emailAddress>[email protected]</emailAddress>
    </userAccountDetail>
 </user>
</users>

My Spring Batch Configuration

<batch:job id="walletUsersImportJob">
        <batch:step id="importUsers" allow-start-if-complete="true">
            <batch:tasklet>
                <batch:chunk reader="xmlItemReader" writer="userDetailWriter"
                    processor="userDetailProcessor" commit-interval="2147483647">
                </batch:chunk>
            </batch:tasklet>
            <batch:listeners>
                <batch:listener>
                    <bean
                        class="com.masterpass.datamigration.batch.core.listener.ItemFailureHandler" />
                </batch:listener>
            </batch:listeners>
        </batch:step>
    </batch:job>

DataSource Configuration

<bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="routingDataSource" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="true" />
            </bean>
        </property>
</bean>



<bean id="routingDataSource"     
class="com.csam.wsc.enabling.tenant.jdbc.datasource.lookup.TenantRoutingDataSource"  >
        <property name="defaultTargetDataSource" ref="globalDataSource"/>
        <property name="tenantMetadataLookupStrategy" ref="tenantMetadataLookupStrategy" />
    </bean>

Here tenantMetadataLookupStrategy needs to be looked for tenant identifier i.e tenantId received as a part of XML and I have a map like

tenantId = Datasource

acmebank = java:/ACMEBANK_DS
anybank = java:/ANYBANK_DS

which will give me which database to be used for any DAO operation.

Hope configurations wise I am fine.

Let me tell my problem.

When Spring batch application boot strap, org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource.determineTargetDataSource() called which needs tenantID to identify target datasource.

This tenantID, I have in XML and will not be available until ItemReader complete.

My Spring Batch configuration using batch:tasklet which surrounds reader, writer, and processor in a single transaction.

Due to above, during boot strap I suspect when initializing transaction manager , entityManagerFactory looks for datasource i.e routingDataSource and which in turn needed on tenantId.

I think if I remove reader and processor from transaction body, I will get some place to capture tenantId and set it in context somewhere so that it can select DB at runtime.

Even I do not want reader & processor transnational aware so better If I can wrap only writer in transaction.

Please suggest.

1

1 Answers

0
votes

Two things here:

  1. To "remove the read and process from the transaction body" in Spring Batch is virtually impossible. You'd have to rewrite the TaskletStep (one of the most sensitive pieces of code in the framework) which I would not recommend.
  2. I believe you are correct in the reason the routing data source isn't working. That being said, I'd actually recommend a slightly different approach. Instead of using the routing data source technique, why not use the ClassifierCompositeItemWriter? This moves the routing up a level (from the connection to the item writer) which allows each writer instance to obtain a connection for the life of the transaction.

You can read more about the ClassifierCompositeItemWriter in the javadoc here: http://docs.spring.io/spring-batch/trunk/apidocs/org/springframework/batch/item/support/ClassifierCompositeItemWriter.html