gavlyukovskiy/spring-boot-data-source-decorator

p6spy disturb Routing Datasource to Read-Only Database

uHan2 opened this issue · 5 comments

uHan2 commented

hello im using 1.5.8 version.

image

and this is call stack snapshot in debug mode on intelliJ

as you can see, the step is

start transaction -> get connection on datasource -> "get connection and get MetaData by p6spy" -> determineCurrentLookUpKey (Actual Routing point)

in my expect, the next step of determineCurrentLookUpKey (Actual Routing point) is get new connection
but it use the connection which was get by p6spy.

when if i remove this dependency, it works fine.

so how can i solve this issue? thank you :)

Hey, I don't quite understand what is the problem that you're seeing. The fact that you see p6spy connection is expected as it proxies the actual connection, but all the operations are still going through your RoutingDataSource.
Can you please provide an example of something not working (i.e. query goes to a wrong route or some exception)?

uHan2 commented

@gavlyukovskiy

image

Here is DataSource Type. as you can see i wrapped AbstractRoutingDataSource by LazyConnectionDataSourceProxy

boolean isReadOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();

this code Is a condition that transaction is readonly or not

image

and this is a partial of AbstractPlatformTransactionManager

TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());

at this line, transaction is set readonly or not

the normal step is

TransactionSynchronizationManager.setCurrentTransactionReadOnly() -> TransactionSynchronizationManager.isCurrentTransactionReadOnly()

but, when i use p6spy,

TransactionSynchronizationManager.isCurrentTransactionReadOnly() comes first (i think because p6spy should get connection) -> TransactionSynchronizationManager.setCurrentTransactionReadOnly() -> X (not going to TransactionSynchronizationManager.isCurrentTransactionReadOnly())

i think the transaction manager use the connection which already get by p6spy

when i remove p6spy, it works normally

im korean and my english little poor. I ask for your understanding. thank you :)

Thanks for the example, it seems to be more complicated that I initially anticipated so I will have to allocate some time to get to it and find a reason. I'm quite busy at the moment, so I won't be able to provide any ETA.

Meanwhile I think one way you can workaround that is to exclude your lazy/routing data source from decoration using decorator.datasource.exclude-beans: dataSource and instead rely on decoration of primaryDataSource and readonlyDataSource (so that each will be wrapped into individual P6DataSource), but keep in mind that they have to be spring beans to pass through decoration phase.

im korean and my english little poor. I ask for your understanding. thank you :)

No worries 🙂 I could understand you well. And thank you again for the detailed explanation!

uHan2 commented

@gavlyukovskiy

thank you for your answer :)
i will try later that way you suggested.

If you solve this problem later when you have time, please mention me on this issue. thank you 👍

uHan2 commented

@gavlyukovskiy

oh my god .. it works!

I'm not sure I fully understand what you're saying, but i tried below things

  • add decorator.datasource.exclude-beans: getDataSource in my application.yml (in my case the bean name is getDataSource)
  • make primary Database and readonly Database to spring beans

and it works! but It's hard to understand why this is working normally

two datasource was not a spring beans when i issue it. and now it becomes beans so is it wrapped into p6Datasource each?

and i exclude my origin datasource which return new LazyConnectionDataSourceProxy(routingDataSource);
then i wonder how spring routing my transaction...

it works but it hard to understand why..
If you don't mind, I'll ask you to explain. and really appreciate for your hint to solve