Skip to content
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

EclipseLinkJpaDialect: Unexpected default isolation levels #29997

Closed
avgustinmm opened this issue Feb 20, 2023 · 5 comments
Closed

EclipseLinkJpaDialect: Unexpected default isolation levels #29997

avgustinmm opened this issue Feb 20, 2023 · 5 comments
Assignees
Labels
in: data Issues in data modules (jdbc, orm, oxm, tx) status: backported An issue that has been backported to maintenance branches type: bug A general bug
Milestone

Comments

@avgustinmm
Copy link

avgustinmm commented Feb 20, 2023

Affects: 6.0.4
(and before)


It seems that in some cases EclipseLinkJpaDialect doesn't handle correctly isolation levels.
For instance in the following flow:

  1. Execute transaction with SERIALIZABLE isolation level -> EclipseLinkJpaDialect#beginTransaction sets to DatabaseLogin / DatabasePlatform the isolation level and probably all is ok and the SERIALIZABLE isolation level is applied. After that transaction the DatabasePlatform's isolation level isn't cleared / reset and stays SERIALIZABLE
  2. Then start a new transaction with DEFAULT isolation level which, according to documentation, should be the default isolation of the underlying database. However, since EclipseLinkJpaDialect#beginTransaction doesn't do anything with isolation levels (when used DEFAULT) the isolation level in DatabasePlatform stays SERIALIZABLE and it seems that isolation level is used instead of DEFAULT.

I suppose that EclipseLinkJpaDialect#beginTransaction should set the DEFAULT isolation level to DatabasePlatform instead explicitly doing nothing in that case. Or, somehow DatabasePlatform's isolation level shall be reset after transaction.

I'm attaching a reproducer (reproducer.zip, main method to be considered is Reproducer#repoduce) that shows that:

  • before first transaction the DatabasePlatform isolation level is -1 (DEFAULT)
  • after a transaction with SERIALIZABLE isolation level in the DatabasePlatform stays SERIALIZABLE - not reset
  • the method reproduce fails (against mysql) with:

com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

  • when however line 40 (entityManager.unwrap(UnitOfWork.class).getPlatform().setTransactionIsolation(-1);) is uncommented and default level is reset to -1 (as at the beginning) the reproduce method passes. So we have different behavior of depending on the DatabasePlatform's isolation level before the last 2 transactions
  • If you comment / remove the first transaction (SERIALIZABLE) and execute just the last 2 transactions - reproduce passes. So, the behavior of the last 2 transaction is influenced by the first one - which should not be the case

Note: reproducer is configured to use local mysql database (see the application properties) .

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Feb 20, 2023
@jhoeller jhoeller added the in: data Issues in data modules (jdbc, orm, oxm, tx) label Feb 21, 2023
@jhoeller jhoeller self-assigned this Feb 21, 2023
@jhoeller
Copy link
Contributor

Relates to #24802 - the isolation level support for EclipseLink is somewhat broken and only really works properly in single-threaded scenarios with consistent isolation level declarations. We need to revisit what we're doing about isolation levels there: It might be better to deprecate isolation level support with EclipseLink to begin with - since we do not have APIs for proper per-transaction transaction isolation there but rather apparently just a system-wide shared isolation level setting in DatabaseLogin.

@jhoeller jhoeller added type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Jun 3, 2023
@jhoeller jhoeller modified the milestones: 6.1.x, 6.0.10 Jun 3, 2023
@jhoeller jhoeller added type: bug A general bug for: backport-to-5.3.x Marks an issue as a candidate for backport to 5.3.x and removed type: enhancement A general enhancement labels Jun 4, 2023
@github-actions github-actions bot added status: backported An issue that has been backported to maintenance branches and removed for: backport-to-5.3.x Marks an issue as a candidate for backport to 5.3.x labels Jun 4, 2023
@jhoeller
Copy link
Contributor

jhoeller commented Jun 4, 2023

Since EclipseLink applies a custom transaction isolation value to its shared DatabasePlatform instance, we need to restore the original shared value afterwards. We set and reset the shared isolation value within a synchronized transaction begin sequence in EclipseLinkJpaDialect now (only in case of a custom isolation level specified) in order to neither interfere with subsequent nor with concurrent transactions. This comes at a bit of synchronization cost but since we're only paying that for actual custom transaction isolations, it should be worth making it work properly that way.

jhoeller added a commit that referenced this issue Jun 4, 2023
…begin

Since EclipseLink applies a custom transaction isolation value to its shared DatabasePlatform instance, we need to immediately restore the original value after the current value got picked up for JDBC Connection access inside of EclipseLink. In order to not interfere with concurrent transactions, we need to use synchronization around the transaction begin sequence in such a case.

Closes gh-29997
@avgustinmm
Copy link
Author

Hi,
sorry for commenting a closed issue but I think there still has a problem with isolation levels and concurrency.
AFAIU, after the fix a default isolation level transaction could run concurrently with a custom isolation level transaction hence could use the set custom isolation level instead of the default.

@jhoeller
Copy link
Contributor

jhoeller commented Jun 13, 2023

Good point, this can be improved through identical synchronization around the beginEarlyTransaction call for the default isolation case. So this can work reliably for non-readOnly and non-lazy transaction scenarios at least. For the rest, we should document a potential isolation level mismatch in the default case which might be acceptable for read-only scenarios. In any case, read-only as well as lazy transactions are entirely opt-in - and not typically used in isolation level scenarios, I suppose.

@jhoeller jhoeller reopened this Jun 13, 2023
@jhoeller
Copy link
Contributor

The additional synchronization applied to the regular non-lazy transaction begin case is making it into 6.0.10 now, whereas the 5.3.28 backport will remain limited to the original purpose of a more reliable code path for consistent isolation level usage (while leaving the default code path untouched). Corresponding documentation of the care to be taken will be available in the javadoc.

mdeinum pushed a commit to mdeinum/spring-framework that referenced this issue Jun 29, 2023
…begin

Since EclipseLink applies a custom transaction isolation value to its shared DatabasePlatform instance, we need to immediately restore the original value after the current value got picked up for JDBC Connection access inside of EclipseLink. In order to not interfere with concurrent transactions, we need to use synchronization around the transaction begin sequence in such a case.

Closes spring-projectsgh-29997
mdeinum pushed a commit to mdeinum/spring-framework that referenced this issue Jun 29, 2023
mdeinum pushed a commit to mdeinum/spring-framework that referenced this issue Jun 29, 2023
Lazy and read-only database transactions remain exposed to potential isolation level mismatches in case of concurrent transactions with custom isolation levels.

Closes spring-projectsgh-29997
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: data Issues in data modules (jdbc, orm, oxm, tx) status: backported An issue that has been backported to maintenance branches type: bug A general bug
Projects
None yet
Development

No branches or pull requests

3 participants