-
Notifications
You must be signed in to change notification settings - Fork 198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
javax.transaction.Transactional does not work at the individual method level #1293
Comments
We would need to have some annotation like |
Couldn't the interceptor just bypass the single connection/transactional data source when a call to get a connection comes outside a transaction context? The error shows that we know we're outside a transaction context. |
The error might be misleading, we don't need to have a transaction but we do need to have a connection. Right now we have an interceptor of the Connection interface that delegates to the existing open connection that is initialized when the transactional annotation is added. |
Well, in my case the error diagnoses the problem correctly (not in a transaction), but the resolution advice is just plain wrong. It is absolutely reasonable, given the accepted usage of javax.transaction.Transactional, to have non-transactional methods on a class that also has transactional methods. As a workaround for the lack of a connection, we found that using io.micronaut.transaction.annotation.ReadOnly on non-transactional methods avoids the error. So, at an absolute minimum, the advice the exception gives needs to mentioned this option. That said, the implementation around javax.transaction.Transactional is still not correct in that the effect of setting a transaction context on a method extends way beyond the bounds of the annotated method. |
Transaction advice doesn’t affect other methods. You are injecting a connection which in the current implementation delegates to the connection from the transaction, that’s why you get an exception when it’s missing. In any case there needs to be some aspect that would open and close the data source connection. Different people requested for JDBC implementation to be used without transactions around, so I want to introduce a connection aspect for that. |
@dstepanov I came across this while trying to get to the bottom of transaction issues described in micronaut-sql#558. Essentially I had problems getting I created a sample project and in the I'm not sure what to take away from the above conversation. Is this not possible or should I just be doing it differently? I recently upgraded to Micronaut 3 and before that I'm quite sure this was working (albeit with transaction management from Spring). Any tips would be appreciated! |
@matt-snider Can you please provide a test inside of the project with testcontainers. |
@dstepanov I can provide this if you think it's necessary. There are steps to reproduce in the comment above the controller. It only takes 3 curl requests so reproduction is very straight forward. To be clear, I'm willing to write the tests I just want to make sure you actually need this before I spend the time. I need to fix the error I'm getting on test ("Could not create task ':testNativeImage'. The value for this property is final and cannot be changed any further.") and figure out how to use testcontainers, since I've never used them. |
we need a reproducer yes |
@matt-snider Yes please, I prefer a reproducer that doesn’t require me running some db locally. You might try to use the latest micronaut plugin |
@dstepanov @graemerocher Sure, I will provide that. Did you look at the example controller though? It just runs H2 so there is no need to run any db locally |
@dstepanov I added a test to the repo linked above. I didn't use test containers because the issue is reproducible with H2. |
@matt-snider Sorry I didn't realize it on the first look. Your issue is the same as that of the reporter, Now, what exactly would you expect to happen in the case without a transaction? In my opinion, we should call |
@dstepanov Thank you for taking a look and explaining! I appreciate it. I would have expected it to work like Spring's In the example project, I changed to Spring in this commit and everything worked as expected after that. So at least on my end it's not a big deal to just switch to Spring Transaction Management |
@matt-snider I have debugged the Spring TX and I see the difference. The original poster is injecting That can be fixed, can you please create a new issue? |
@dstepanov Thank you for looking into this! I've created #1399 |
@dstepanov Actually, the original reporter is injecting javax.sql.DataSource in the situation that lead to this problem entry. The reproduction example does inject java.sql.Connection, but the bottom line is the same as with Connection injection, the logic has to be request scoped. In the end, both the injected DataSource and Connection are wrappers with logic inside them to provide the actual resources when appropriate and that logic is driven by micronaut design decisions. As you've noted, the micronaut design produces behavior that is decidedly different than that produced by the spring based alternative. I think this is a mistake and arguably a bug, but as you have also noted, at an absolute minimum it should be documented in detail so that users know what to expect. |
@Jim-Harrington If you are actually using the datasource to get the connection the fix should be for both issues. In Micronaut we allow injecting the connection which Spring doesn't support so that's the confusion. |
@dstepanov @Jim-Harrington Perhaps you can suggest a better title for #1399 if it isn't JOOQ specific. |
@matt-snider Given that annotating the non-transactional methods with io.micronaut.transaction.annotation.ReadOnly avoids this trouble, it shows that spring tx like behavior is possible using native micronaut tx. My suggestion for a solution would be to have methods on transactional classes that don't carry @transactional see behavior that equivalent to what they get if annotated with @readonly. In other words, transactional behavior should apply only to methods that have declared their desire for it by being annotated with @transactional. |
@Jim-Harrington |
While trying to set up db-scheduler with Micronaut & transactions I encountered the same issue. Since I spent considerable time trying to marry those, I wanted to share a fairly simple solution to my problem in hope that it might be helpful to someone experiencing the same problem. I've shared it in this StackOverflow answer but posting relevant bits here (just in case anything happens with the link). Basically I have this adapter method: private fun configureDataSource(dataSource: DataSource): DataSource {
// Is transaction-aware DataSource proxy active? (Note: class is private so we match by name)
return if (dataSource::class.qualifiedName == "io.micronaut.transaction.jdbc.TransactionAwareDataSource.DataSourceProxy") {
log.info("Adding support for out-of-transaction connection fetching since the data source is a TransactionAwareDataSource")
object : DelegatingDataSource(dataSource) {
override fun getConnection() =
if (TransactionSynchronizationManager.isSynchronizationActive()) dataSource.connection
else DelegatingDataSource.unwrapDataSource(dataSource).connection
}
} else {
dataSource
}
} It detects if the
I then pass this adapted |
@apankowski You can simple you |
Closing this issue as the transaction manager has been rewritten in the V4. |
Expected Behavior
That methods carrying the javax.transaction.Transactional annotation run in a transaction with a configuration matching the parameters specified in the annotation and that methods not carrying the javax.transaction.Transactional successfully run outside a transaction context.
javax.transaction.Transactional is clearly intended to be a method level annotation, so it must be possible to non-transactional methods on a class.
Actual Behaviour
Methods not carrying the javax.transaction.Transactional annotation fail with:
Steps To Reproduce
As an example, I modified the test case: data-tx:io.micronaut.transaction.jdbc.TransactionAnnotationSpec as follows:
and get this when running:
Environment Information
Mac OS
JDK 11
Example Application
No response
Version
micronaut parent 3.2.1, but I tried version 3.2.7 of the parent and got the same result
The text was updated successfully, but these errors were encountered: