问题
The Django docs for select_for_update say
Using select_for_update() on backends which do not support SELECT ... FOR UPDATE (such as SQLite) will have no effect. SELECT ... FOR UPDATE will not be added to the query, and an error isn’t raised if select_for_update() is used in autocommit mode.
This strikes me as an odd and potentially dangerous decision, especially since select_for_update
is used to lock rows. If I write code that uses select_for_update
, I would rely on it actually being honored! If the DB backend doesn't support it, I would expect Django to either fall back to a safe-but-less-efficient alternative or, if one doesn't exist, to throw an exception of some kind.
In this case it seems like Django could suddenly and silently reintroduce race conditions by just ignoring select_for_update
on DBs where it's not supported (such as SQLite). My intuition says Django wouldn't do that and there must be some reason why it's not needed if not supported (perhaps engines where it's not supported use complete database locking?) but I can't seem to find anything concrete in the docs to back up that theory. It doesn't seem like this issue is necessarily specific to Django, either.
This is making me very leery of using select_for_update
even though it would solve some current problems nicely.
回答1:
With database engines that allow to reduce transaction isolation in order to improve the speed of concurrent accesses (e.g., PostgreSQL, Oracle, and MySQL), SELECT FOR UPDATE is used to tell the database that rows that are read now will likely be written to later. This can avoid inconsistent data showing up in concurrent transactions, or even prevent deadlocks in some situations.
In SQLite, all transactions are serializable, i.e., it behaves as if the entire database is locked around each transaction. (And in autocommit mode, each statement is wrapped in an implicit transaction.)
So SELECT FOR UPDATE, even if it were implemented, would not actually add any more locking than is already there. Ignoring it is the right thing to do for SQLite.
回答2:
Think of it from this perspective.
You've just installed a library from github and want to try it out quickly using the default mysqlite settings - but you can't use it because they happen to use select_for_update
in one spot. Would you rather the package worked (but with the possibility of a race condition) or explode in your face?
The Django team makes many compromises in order to get their product working in all of the different configurations it supports. Ideally, Django applications are supposed to be able to be dropped into any of them. If race-conditions become an issue for a developer, then it won't take a lot of research until they realise that they are using an unsuitable backend, and will have to switch to one that is more appropriate for the task at hand.
In other words, Django favours compatibility over functionality in this instance.
Django could suddenly and silently reintroduce by just ignoring select_for_update
It won't introduce them suddenly - changing database backends is not something one does accidentally - and in production environments it's often a non-trivial task. We're not rolling dice here. If a developer chooses to change databases then it is a good idea for them to research the pros and cons of that database - and test it.
来源:https://stackoverflow.com/questions/46945790/why-could-select-for-update-simply-be-ignored-with-databases-that-dont-support