Skip to content
Advertisement

Spring dynamically choosing between data sources (alternative to ThreadLocal)

I’ve read about AbstractRoutingDataSource and the standard ways to bind a datasource dynamically in this article:

JavaScript

It uses a ThreadLocal context holder to “set” the DataSource:

JavaScript

I have a quite complex system where threads are not necessarily in my control, say:

  • Scheduled EJB reads a job list from the database
  • For each Job it fires a Spring (or Java EE) batch job.
  • Each job have its origin and destination databases (read from a central database).
  • Multiple jobs will run in parallel
  • Jobs may be multithreaded.
  • ItemReader will use the origin data source that was set for that specific job (origin data source must be bound to some repositories)
  • ItemWriter will use the destination data source that was set for that specific job (destination data source must also be bound to some repositories).

So I’m feeling somewhat anxious about ThreadLocal, specially, I’m not sure if the same thread will be used to handle multiple jobs. If that happens origin and destination databases may get mixed.

How can I “store” and bind a data source dynamically in a safe way when dealing with multiple threads?

Advertisement

Answer

I could not find a way to setup Spring to play nice with my setup and inject the desired DataSource, so I’ve decided to handle that manually.

Detailed solution:

  1. I changed my repositories to be prototypes so that a new instance is constructed every time that I wire it:

    JavaScript
  2. I’ve introduced new setDataSource and setSchema methods in top level interfaces / implementations that are supposed to work with multiple instances / schemas.

  3. Since I’m using spring-data-jdbc-repository my setDataSource method simple wraps the DataSource with a new JdbcTemplate and propagate the change.

    JavaScript
  4. My implementation is obtaining the DataSources directly from the application server:

    JavaScript
  5. Finally, for multiples schemas under the same database instance, I’m logging in with a special user (with the correct permissions) and using a Oracle command to switch to the desired schema:

    JavaScript

While this goes against the Dependency inversion principle it works and is handling my concurrency requirements very well.

Advertisement