Opened 10 years ago
Closed 9 years ago
#26541 closed Cleanup/optimization (fixed)
Add a DatabaseFeatures.supports_transactions() method for MySQL
| Reported by: | Marcin Nowak | Owned by: | Mariusz Felisiak |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 1.8 |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Ready for checkin | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
When something goes wrong during checking database features, the state of db stays affected:
File "/home/marcin/myproject/eggs/Django-1.8.6-py2.7.egg/django/test/testcases.py", line 182, in __call__
self._pre_setup()
File "/home/marcin/myproject/eggs/Django-1.8.6-py2.7.egg/django/test/testcases.py", line 787, in _pre_setup
self._fixture_setup()
File "/home/marcin/myproject/eggs/Django-1.8.6-py2.7.egg/django/test/testcases.py", line 986, in _fixture_setup
if not connections_support_transactions():
File "/home/marcin/myproject/eggs/Django-1.8.6-py2.7.egg/django/test/testcases.py", line 911, in connections_support_transactions
for conn in connections.all())
File "/home/marcin/myproject/eggs/Django-1.8.6-py2.7.egg/django/test/testcases.py", line 911, in <genexpr>
for conn in connections.all())
File "/home/marcin/myproject/eggs/Django-1.8.6-py2.7.egg/django/utils/functional.py", line 59, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "/home/marcin/myproject/eggs/Django-1.8.6-py2.7.egg/django/db/backends/base/features.py", line 217, in supports_transactions
cursor.execute('CREATE TABLE ROLLBACK_TEST (X INT)')
File "/home/marcin/myproject/eggs/Django-1.8.6-py2.7.egg/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/home/marcin/myproject/eggs/Django-1.8.6-py2.7.egg/django/db/utils.py", line 97, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/home/marcin/myproject/eggs/Django-1.8.6-py2.7.egg/django/db/backends/utils.py", line 62, in execute
return self.cursor.execute(sql)
File "/home/marcin/myproject/eggs/Django-1.8.6-py2.7.egg/django/db/backends/mysql/base.py", line 124, in execute
return self.cursor.execute(query, args)
File "/home/marcin/myproject/eggs/MySQL_python-1.2.3-py2.7-linux-x86_64.egg/MySQLdb/cursors.py", line 174, in execute
self.errorhandler(self, exc, value)
File "/home/marcin/myproject/eggs/MySQL_python-1.2.3-py2.7-linux-x86_64.egg/MySQLdb/connections.py", line 36, in defaulterrorhandler
raise errorclass, errorvalue
OperationalError: (1050, "Table 'ROLLBACK_TEST' already exists")
- Django should not create any table during startup - there may be readonly or sensitive databases connected
- Let the Django do some cleanups, if it must "dig" databases.
Change History (7)
comment:1 by , 10 years ago
| Summary: | Table 'ROLLBACK_TEST' already exists → Add a DatabaseFeatures.supports_transactions() method for MySQL |
|---|---|
| Type: | Bug → Cleanup/optimization |
comment:2 by , 10 years ago
Tim, what about transaction handling where MyISAM engine is set per table?
Checking transaction handling by table creation does not cover this use case, same as general property of the connection.
So in that case I'd like to see this cleanup as a property/parameter instead of sniffing feature by table creation (because it is safer and configurable).
But if you'd like to be perfect you should always inspect transaction (an atomic session) and raise exception when user is trying to modify "non-transactional" table. In that case every model should "support_transaction" or not, and this seems like a design change.
In the other side I'm opposed to MySQL`s engines concept and I'm always trying to avoid this database where possible. So from my point of view it is enough to assume that MySQL supports transactions (or not), and allow to change this property by the user using some OPTION in engine configuration.
comment:3 by , 10 years ago
| Triage Stage: | Unreviewed → Accepted |
|---|
I don't have much MySQL expertise so I'm afraid I can't advise much here but I don't think Django needs to support the use case of per table transaction handling. If someone has such a need, perhaps that could be accomplished by routing to different database aliases.
As a workaround until a solution lands in Django, you could create your own MySQL backend that sets support_transaction as you like. Unless a discussion on the DevelopersMailingList reaches a different consensus, I don't think adding something in OPTIONS makes sense given that this doesn't seem to be much of an issue as far as tell. I haven't seen anyone else hit this problem since the current technique was introduced in Django 1.1 (344f16e2205a4959ba65d975716a38db77d2061e).
comment:4 by , 10 years ago
As a workaround until a solution lands in Django, you could create your own MySQL backend that sets support_transaction as you like.
It sound good. Thanks.
comment:5 by , 9 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
comment:6 by , 9 years ago
| Triage Stage: | Accepted → Ready for checkin |
|---|
For Django's built in database backends, this issues seems to be limited to MySQL as the other built in database backend set
DatabaseFeatures.supports_transactions = Trueand override the default implementation which does the feature test involving the temporary table indicated in the traceback. Is it feasible to add aDatabaseFeatures.supports_transactions()method for the MySQL backend that detects transaction support by examining the storage engine?