Skip to content

Make LockMode::NONE a no-op - #12548

Open
ruudk wants to merge 1 commit into
doctrine:3.7.xfrom
ruudk:fix-lock-mode-none-refresh
Open

Make LockMode::NONE a no-op#12548
ruudk wants to merge 1 commit into
doctrine:3.7.xfrom
ruudk:fix-lock-mode-none-refresh

Conversation

@ruudk

@ruudk ruudk commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

LockMode::NONE means "no lock", yet two code paths still treated it like a pessimistic lock mode:

  • EntityManager::find() refreshed an entity that was already in the identity map, silently discarding in-memory changes. A caller asking for "no lock" has no reason to expect a reload.
  • UnitOfWork::lock() demanded an active transaction and then executed SELECT 1 FROM <table> WHERE id = ? with no lock hint at all — a query that locks nothing.

Both are leftovers from #932 (2014), when LockMode::NONE made SQL Server emit WITH (NOLOCK) and therefore did affect isolation. DBAL removed that hint in doctrine/dbal#4400 because it "is not the contract of LockMode::NONE", so nothing is left to guard.

EntityManager::refresh(), checkLockRequirements() and (since #12516) Query::setLockMode() already ignore NONE. This aligns the last two.

Follow-up to #12516, and picks up the remainder of the closed #8341.

`LockMode::NONE` means "no lock", yet two code paths still treated it like a
pessimistic lock mode:

- `EntityManager::find()` refreshed an entity that was already in the identity
  map, silently discarding in-memory changes. A caller asking for "no lock"
  has no reason to expect a reload.
- `UnitOfWork::lock()` demanded an active transaction and then executed
  `SELECT 1 FROM <table> WHERE id = ?` with no lock hint at all — a query that
  locks nothing.

Both are leftovers from doctrine#932 (2014), when `LockMode::NONE` made
SQL Server emit `WITH (NOLOCK)` and therefore did affect isolation. DBAL
removed that hint in doctrine/dbal#4400 because it "is not the contract of
`LockMode::NONE`", so nothing is left to guard.

`EntityManager::refresh()`, `checkLockRequirements()` and (since doctrine#12516)
`Query::setLockMode()` already ignore `NONE`. This aligns the last two.

Follow-up to doctrine#12516, and picks up the remainder of the closed doctrine#8341.

@BenMorel BenMorel left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ruudk If I understand correctly, null and LockMode::NONE are now equivalent; should we therefore deprecate passing null as a lock mode?

@ruudk

ruudk commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Yeah good one. Should I do that here or in a new Pr

Comment thread UPGRADE.md
Comment on lines +42 to +45
Both now do nothing, which is consistent with `EntityManager::refresh()` and
`Query::setLockMode()`. If you relied on `find()` reloading the entity, call
`EntityManager::refresh()` explicitly.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, we're changing the behavior hiere, although that behavior is undocumented. How likely do we think it is that existing applications rely on this "hidden feature"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I find it a bit scary to be honest.

So if you would use EntityManager::find(132, LockMode::NONE) it would actually refresh from database while if you did EntityManager::find(123) it would not, if it already exists in the UOW.

What to do?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I find it a bit scary to be honest.

Me too! 🫣

What to do?

I don't know. I don't see a better way forward, tbh. Maybe, this change is acceptable as is, given that the old behavior was unintentional and undocumented.

Either way: If we feel like we need to document this change of behavior in the upgrade document, we should not target a bugfix release. Let's target 3.7.x.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, let's do it in 3.7.x then!

@derrabus
derrabus changed the base branch from 3.6.x to 3.7.x August 7, 2026 10:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants