I was inspired by Carl Papa's use of aspects with the Spring Framework to determine the DataSource
to use (either read-write or read-only). So, I'm writing this post.
I must admit that I have long been familiar with Spring's AbstractRoutingDataSource
. But I did not have a good idea where it can be used. Thanks to Carl and team, and one of their projects. Now, I know a good use case.
@Transactional
With Spring, read-only transactions are typically marked with annotations.
public class ... { @Transactional(readOnly=true) public void ...() {...} @Transactional // read-write public void ...() {...} }
To take advantage of this, we use Spring's TransactionSynchronizationManager
to determine if the current transaction is read-only or not.
AbstractRoutingDataSource
Here, we use Spring's AbstractRoutingDataSource
to route to the read-only replica if the current transaction is read-only. Otherwise, it routes to the default which is the master.
public class ... extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { if (TransactionSynchronizationManager .isCurrentTransactionReadOnly() ...) { // return key to a replica } return null; // use default } ... }
Upon using the above approach, we found out that the TransactionSynchronizationManager
is one step behind because Spring will have already called DataSource.getConnection()
before a synchronization is established. Thus, a LazyConnectionDataSourceProxy
needs to be configured as well.
As we were discussing this, we figured if there was another way to determine if the current transaction is read-only or not (without resorting to LazyConnectionDataSourceProxy
). So, we came up with an experimental approach where an aspect captures the TransactionDefinition
(from the @Transactional
annotation, if any) as a thread-local variable, and an AbstractRoutingDataSource
that routes based on the captured information.
The relevant source code can be found on GitHub. Thanks again, Carl! BTW, Carl is also an award-winning movie director. Wow, talent definitely knows no boundaries.
No comments:
Post a Comment