.. changelog::
:version: 1.1.0b1
+ .. change::
+ :tags: feature, mysql
+ :tickets: 3332
+
+ Added support for "autocommit" on MySQL drivers, via the
+ AUTOCOMMIT isolation level setting. Pull request courtesy
+ Roman Podoliaka.
+
+ .. seealso::
+
+ :ref:`change_3332`
+
.. change::
:tags: bug, orm
:tickets: 3677
:ticket:`3547`
+.. _change_3332:
+
+Added support for AUTOCOMMIT "isolation level"
+----------------------------------------------
+
+The MySQL dialect now accepts the value "AUTOCOMMIT" for the
+:paramref:`.create_engine.isolation_level` and
+:paramref:`.Connection.execution_options.isolation_level`
+parameters::
+
+ connection = engine.connect()
+ connection = connection.execution_options(
+ isolation_level="AUTOCOMMIT"
+ )
+
+The isolation level makes use of the various "autocommit" attributes
+provided by most MySQL DBAPIs.
+
+:ticket:`3332`
.. _change_mysql_3216:
Transaction Isolation Level
---------------------------
-:func:`.create_engine` accepts an :paramref:`.create_engine.isolation_level`
-parameter which results in the command ``SET SESSION
-TRANSACTION ISOLATION LEVEL <level>`` being invoked for
-every new connection. Valid values for this parameter are
-``READ COMMITTED``, ``READ UNCOMMITTED``,
-``REPEATABLE READ``, and ``SERIALIZABLE``::
+All MySQL dialects support setting of transaction isolation level
+both via a dialect-specific parameter :paramref:`.create_engine.isolation_level`
+accepted by :func:`.create_engine`,
+as well as the :paramref:`.Connection.execution_options.isolation_level`
+argument as passed to :meth:`.Connection.execution_options`.
+This feature works by issuing the command
+``SET SESSION TRANSACTION ISOLATION LEVEL <level>`` for
+each new connection. For the special AUTOCOMMIT isolation level, DBAPI-specific
+techniques are used.
+
+To set isolation level using :func:`.create_engine`::
engine = create_engine(
"mysql://scott:tiger@localhost/test",
isolation_level="READ UNCOMMITTED"
)
-.. versionadded:: 0.7.6
+To set using per-connection execution options::
+
+ connection = engine.connect()
+ connection = connection.execution_options(
+ isolation_level="READ COMMITTED"
+ )
+
+Valid values for ``isolation_level`` include:
+
+* ``READ COMMITTED``
+* ``READ UNCOMMITTED``
+* ``REPEATABLE READ``
+* ``SERIALIZABLE``
+* ``AUTOCOMMIT``
+
+The special ``AUTOCOMMIT`` value makes use of the various "autocommit"
+attributes provided by specific DBAPIs, and is currently supported by
+MySQLdb, MySQL-Client, MySQL-Connector Python, and PyMySQL. Using it,
+the MySQL connection will return true for the value of
+``SELECT @@autocommit;``.
+
+.. versionadded:: 1.1 - added support for the AUTOCOMMIT isolation level.
AUTO_INCREMENT Behavior
-----------------------
level = level.replace('_', ' ')
# adjust for ConnectionFairy being present
+ # allows attribute set e.g. "connection.autocommit = True"
+ # to work properly
if hasattr(connection, 'connection'):
connection = connection.connection
All Postgresql dialects support setting of transaction isolation level
both via a dialect-specific parameter :paramref:`.create_engine.isolation_level`
accepted by :func:`.create_engine`,
-as well as the ``isolation_level`` argument as passed to
+as well as the :paramref:`.Connection.execution_options.isolation_level` argument as passed to
:meth:`.Connection.execution_options`. When using a non-psycopg2 dialect,
this feature works by issuing the command
``SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL <level>`` for
-each new connection.
+each new connection. For the special AUTOCOMMIT isolation level, DBAPI-specific
+techniques are used.
To set isolation level using :func:`.create_engine`::
* ``READ UNCOMMITTED``
* ``REPEATABLE READ``
* ``SERIALIZABLE``
-
-The :mod:`~sqlalchemy.dialects.postgresql.psycopg2` and
-:mod:`~sqlalchemy.dialects.postgresql.pg8000` dialects also offer the
-special level ``AUTOCOMMIT``.
+* ``AUTOCOMMIT`` - on psycopg2 / pg8000 only
.. seealso::
class DialectTest(fixtures.TestBase):
__backend__ = True
+ __only_on__ = 'mysql'
def test_ssl_arguments_mysqldb(self):
from sqlalchemy.dialects.mysql import mysqldb
conn = eng.connect()
eq_(conn.dialect._connection_charset, enc)
+ def test_autocommit_isolation_level(self):
+ c = testing.db.connect().execution_options(
+ isolation_level='AUTOCOMMIT'
+ )
+ assert c.execute('SELECT @@autocommit;').scalar()
+
+ c = c.execution_options(isolation_level='READ COMMITTED')
+ assert not c.execute('SELECT @@autocommit;').scalar()
+
+ def test_isolation_level(self):
+ values = {
+ # sqlalchemy -> mysql
+ 'READ UNCOMMITTED': 'READ-UNCOMMITTED',
+ 'READ COMMITTED': 'READ-COMMITTED',
+ 'REPEATABLE READ': 'REPEATABLE-READ',
+ 'SERIALIZABLE': 'SERIALIZABLE'
+ }
+ for sa_value, mysql_value in values.items():
+ c = testing.db.connect().execution_options(
+ isolation_level=sa_value
+ )
+ assert c.execute('SELECT @@tx_isolation;').scalar() == mysql_value
+
class SQLModeDetectionTest(fixtures.TestBase):
__only_on__ = 'mysql'
__backend__ = True
d = testing.db.scalar(func.sysdate())
assert isinstance(d, datetime.datetime)
- @testing.only_on(['mysql+mysqldb',
- 'mysql+mysqlconnector',
- 'mysql+pymysql',
- 'mysql+cymysql'])
- def test_autocommit_isolation_level(self):
- c = testing.db.connect().execution_options(
- isolation_level='AUTOCOMMIT'
- )
- assert c.execute('SELECT @@autocommit;').scalar()
-
- def test_isolation_level(self):
- values = {
- # sqlalchemy -> mysql
- 'READ UNCOMMITTED': 'READ-UNCOMMITTED',
- 'READ COMMITTED': 'READ-COMMITTED',
- 'REPEATABLE READ': 'REPEATABLE-READ',
- 'SERIALIZABLE': 'SERIALIZABLE'
- }
- for sa_value, mysql_value in values.items():
- c = testing.db.connect().execution_options(
- isolation_level=sa_value
- )
- assert c.execute('SELECT @@tx_isolation;').scalar() == mysql_value