Describe the bug
A test creates, updates and reads the entity in separate transactions. The last transaction, which reads the entity, can find it, but the entity still has the same value as when it was created.
Expected behavior
After an entity is updated in one transaction, the change should be visible in the next transaction.
Actual behavior
After an entity is updated in one transaction, it has the same value as when it was created.
To Reproduce
Steps to reproduce the behavior:
@Transactional, while called methods are. Configuration
quarkus.datasource.driver=org.h2.Driver
quarkus.datasource.url=jdbc:h2:file:./persons
quarkus.datasource.username=sa
quarkus.datasource.password=sa
quarkus.hibernate-orm.database.generation=drop-and-create
Screenshots
(If applicable, add screenshots to help explain your problem.)
Environment (please complete the following information):
uname -a or ver: Microsoft Windows [Version 10.0.19041.21]java -version: 1.8Additional context
The reproducer is attached:
test-update2.zip
In your test you have @Transactional on a method that is called by other methods on the same class. CDI interceptors are not applied for self invocation, only for external invocation (e.g. when you inject the bean and invoke on it). As no transaction is active this is why the change is not persisted.
@mkouba can you confirm that there are no plans to add support for self-interception? I know this is a topic that comes up every now and then but I can't remember what the spec has to say about it.
Things get a little weird here. If I remove @Transactional and put transaction.begin(); and transaction.commit();, then everything work. If I put @Transactional back on one of the called methods (not the test method, which is called by framework!), I get ARJUNA016051: thread is already associated with a transaction!. A transaction is created even for the self invocation.
transaction.getStatus() = 0, but the results are not as expected. As there are other issues regarding tests and transactions, it would be great if Quarkus team can document transaction strategies for testing in the testing guide.
ok, this is weird, I will investigate
Turns out I was wrong, we do support self invocation for interceptors, so now I have no idea what is going on here, I will investigate further.
@FroMage the test does not seem to be transformed to use the getters/setters, so the dirty checker is not picking up that the entity is dirty.
Well we really need to make sure all the classes that use the entity are transformed as well, otherwise even user-defined accessors won't get called and it will be all confusing.
Today I tried to run my regular tests, which run perfectly under Java 8, under Java 11. The result was a hot mess: half of the tests failed, probably due to some transaction issues. It only happens on Windows, even in WSL2 tests run fine. Should I open a new issue for that or you think that may be related to this issue? To be honest, I do not have a clue about what is going on. Do you test on Windows Java 11?
Here is more: if a class implementing the PanacheRepository is marked as @Transactional, methods injected by Quarkus are not transactional. @FroMage would you consider this as the same issue or different one?
This looks like a different issue.
I believe I am in the same situation, but there is something strange when it is not in test mode too.
I did a test via POSTMAN and with MSSQL database. I followed the request in the database, the entity is updated as expected, but in the application I use the command MyEntity.findAll().list().get(0) and the entity remains not updated.
More informations: #7163
@zeljkot The quarkus-narayana-jta dependency is missing in pom.xml. I added and did tests with TransactionManager and UserTransaction and it didn't solve it. I'm importing from the javax.transaction package, is that correct?
I don't know why the lack of dependency does not generate an error.
In the tests with TransactionManager and UserTransaction the following message started to be displayed when the commit line is executed:
"WARN: Datasource '<default>': Closing open connection prior to commit" #6770
Project with my changes:
https://send.firefox.com/download/318867de387d3f58/#GyyXcEArjnuNlpblvOMqyA
Narayana is dependency of Hibernate, there is no need to include it per se.
My quarkus logs with log trace enabled:
https://send.firefox.com/download/1017dc8221806b4b/#HN3XWg9TzL4hc_db5reZ3Q
Turns out I was wrong, we do support self invocation for interceptors...
@stuartwdouglas Yes, we do. The behavior is undefined from the spec POV.
Here is more: if a class implementing the PanacheRepository is marked as @Transactional, methods injected by Quarkus are not transactional.
@zeljkot Yes, this is a known issue - repository class is transformed/methods are generated and so the CDI container does not see the methods at all. And for entities there is a problem with static methods - these are not intercepted by design (as defined by the spec).
I find a way around this problem, in the test files I did not do operations with the database directly, I did all through API. It worked for me.
Added your test at https://github.com/quarkusio/quarkus/pull/9577 and it passes. We must have fixed this already in master.
Please reopen if you experience this again with 1.5.0.Final due very soon.
I think this was fixed by https://github.com/quarkusio/quarkus/issues/7188
I am still able to reproduce the issue (or at least a very similar one) with Quarkus 1.5.1.Final. The issue on my side seems to hinge on findAll().list() being executed or not, which triggers some kind of TestMethodScoped caching.
See https://github.com/j-be/quarkus-7102 for a minimal project reproducing the issue.
EDIT: I extended the TestProject to better show what I mean with TestMethodScoped, i.e. if the change is checked in a second @Test the entities are indeed updated. I also ran the test against a build of current master (d8ec141d4 with patched dependencyManagement because of the Unsupported api 524288 bug reported in #9832) - still fails.
This is a different issue, and the behaviour you are seeing is expected. The EntityManager will always use the same object for a given ID. When you call findAll that object is loaded from the database. When you edit it in a new transaction the new transaction creates a new EntityManager, however the original EM still has the old entity loaded. When you then call findById the EM just returns the original object loaded by listAll(), which has not been modified yet.
If you want to see the updated object you need to call EntityManager.clear().