| Summary: | JPA and Camel JPA use different transaction scopes in same transaction | ||||||
|---|---|---|---|---|---|---|---|
| Product: | [JBoss] JBoss Fuse Service Works 6 | Reporter: | Daniel Tschan, Puzzle ITC <tschan+redhat> | ||||
| Component: | SwitchYard | Assignee: | Tomohisa Igarashi <toigaras> | ||||
| Status: | CLOSED NOTABUG | QA Contact: | Jiri Sedlacek <jsedlace> | ||||
| Severity: | unspecified | Docs Contact: | |||||
| Priority: | unspecified | ||||||
| Version: | 6.0.0 | CC: | atangrin, jcordes, ldimaggi, oskutka, serviceworks, soa-p-jira, toigaras, tschan+redhat | ||||
| Target Milestone: | --- | ||||||
| Target Release: | --- | ||||||
| Hardware: | Unspecified | ||||||
| OS: | Unspecified | ||||||
| Whiteboard: | |||||||
| Fixed In Version: | Doc Type: | Bug Fix | |||||
| Doc Text: | Story Points: | --- | |||||
| Clone Of: | Environment: | ||||||
| Last Closed: | 2013-11-29 05:57:56 UTC | Type: | Bug | ||||
| Regression: | --- | Mount Type: | --- | ||||
| Documentation: | --- | CRM: | |||||
| Verified Versions: | Category: | --- | |||||
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |||||
| Cloudforms Team: | --- | Target Upstream Version: | |||||
| Attachments: |
|
||||||
It looks like the workaround you suggested is the right approach - letting EntityManagerFactory producer cache the EntityManager and return it for createEntityManager() if you really want to share EntityManager instance between application and camel-jpa. However it would be harmful sometimes since EntityManager is not thread-safe so need to be careful. Anyway, I think there's nothing to do on the SwitchYard side. I think about having a custom camel expressions which maintains a persistent state with JPA, e.g. as part of a dynamic router or dynamic recipient list and a JPA Binding in the same SwitchYard exchange. Aggregators sometimes also maintain a persistent state. Since these are established enterprise integration patterns I think it should at least be documented that there could be issues with transaction scoping. You're right that entity managers are generally not thread safe. However transaction scoped entity managers are by default. That's why I have that crude check in the TransactionScopedEntityManagerFactory constructor. As far as I know there is no standard way to ensure that an entity manager is transaction scoped. However, I don't know what happens if one explicitly associates multiple threads with a single transaction, which is supported by JBossTS. So this might not mix with TransactionScopedEntityManagerFactory. Although I may not understand what you mean by "transaction scope", but I don't recommend sharing EntityManager and expecting it always returns the same instance. Application should be responsible to persist() or merge() to persist the changes it makes. Perhaps this is a better explanation. I'd expect that there is only ever one transaction scoped entity manager associated with a transaction, as is the case in Java EE or Spring applications. The other developers in the project, all experience Java EE and/or Spring developers, have the same expectations. If there are multiple transaction scoped entity managers associated with the same transaction, special care has to be taken because there are now multiple independent first level caches active in the same transaction. The test case actually should test that Camel JPA and JPA use the same transaction scoped entity manager. But since there is no way to get access to a transaction scoped entity manager (you only ever get a delegating proxy) it resorts to compare entity references. This is only a means to demonstrate the issue, not how we implement our applications. Again, application should be responsible to persist() or merge() before the entity is accessed by other components, and find() to acquire latest one after the entity is accessed by other components. Sharing EntityManager doesn't sound a good practice. If you really want to do that, then please take the workaround you suggested in your testcase. We don't try to do anything special and are just using JBoss FSW based on established Enterprise Integration and Java EE patterns. But the transaction scoped entity manager really should be shared by all components in the same transaction. Otherwise "persist" and "merge" will not be enough. You will have to use additional "flush" and "clear" calls to make sure the different first level caches are synchronized, otherwise "find" might not return the latest entity. Developers are not traind and used to do this. Additionally this leads to a loss of performance, because flush involves the database. So far we looked at JBoss FSW as a single development platform and expected the contained components, e.g. SwitchYard and Camel to be integrated accordingly. Are we wrong with this? Looking at FSW as a collection of more or less independent software stacks is of course possible, but makes it much harder to use it. Closing this ticket since it's not a bug report - Tschan, could you post on the FSW6 forum if you want to have a discussion? https://community.jboss.org/en/fsw Or you may be able to get a FSW6 subscription to get the support. Please take a look at this and contact to the sales if you like. http://www.jboss.org/products/fsw.html |
Created attachment 828874 [details] Test case Description of problem: JPA and Camel JPA use different transaction scopes even when running in the same transaction, meaning that there are two first level caches for the same transaction, possibly holding different versions of the same entity. This is not what developers expect and could lead to hard to diagnose problems. The cause of this seems to be that the Spring version used by Camel JPA uses its own transaction scoping mechanism and not the one provided by Java EE. Version-Release number of selected component (if applicable): How reproducible: Always, see attached test case. Steps to Reproduce: 1. Start a standard installation of JBoss Fuse Service Works 6 Beta 2. Make sure you have the JBoss Fuse Service Works 6 Beta Maven repositories configured in your settings.xml 3. Run TransactionScopeTest JUnit/Arquillian test in provided test case Actual results: Test fails because there two instances of the same entity, caused by two entity managers (each with its own cache) associated with the same transaction. Expected results: Test succeeds because there is only one entity manager, therefore only one cache and only one instance of the test entity. Additional info: The test case also contains a workaround for the problem in class TransactionScopedEntityManagerFactory which is demonstrated by the test TransactionScopeWorkaroundTest.