DataSource Routing with Spring @Transactional
source link: https://lorenzo-dee.blogspot.com/2018/01/datasource-routing-with-spring.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
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.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK