Menu:
xa:: XA Transactions
MySQL supports local transactions (within a given client session) through statements such as note 'SET autocommit': commit, note 'START TRANSACTION': commit, note 'COMMIT': commit, and note 'ROLLBACK': commit. See note commit::. XA transaction support enables MySQL to participate in distributed transactions as well. See note xa::.
File: manual.info.tmp, Node: commit, Next: cannot-roll-back, Prev: sql-transactional-statements, Up: sql-transactional-statements
START TRANSACTION
[TRANSACTION_CHARACTERISTIC [, TRANSACTION_CHARACTERISTIC] ...]
TRANSACTION_CHARACTERISTIC: {
WITH CONSISTENT SNAPSHOT
| READ WRITE
| READ ONLY
}
BEGIN [WORK]
COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
SET autocommit = {0 | 1}
These statements provide control over use of transactions:
'START TRANSACTION' or 'BEGIN' start a new transaction.
'COMMIT' commits the current transaction, making its changes permanent.
'ROLLBACK' rolls back the current transaction, canceling its changes.
'SET autocommit' disables or enables the default autocommit mode for the current session.
By default, MySQL runs with autocommit mode enabled. This means that, when not otherwise inside a transaction, each statement is atomic, as if it were surrounded by 'START TRANSACTION' and 'COMMIT'. You cannot use 'ROLLBACK' to undo the effect; however, if an error occurs during statement execution, the statement is rolled back.
To disable autocommit mode implicitly for a single series of statements, use the 'START TRANSACTION' statement:
START TRANSACTION;
SELECT @A:=SUM(salary) FROM table1 WHERE type=1;
UPDATE table2 SET summary=@A WHERE type=1;
COMMIT;
With 'START TRANSACTION', autocommit remains disabled until you end the transaction with 'COMMIT' or 'ROLLBACK'. The autocommit mode then reverts to its previous state.
'START TRANSACTION' permits several modifiers that control transaction characteristics. To specify multiple modifiers, separate them by commas.
The 'WITH CONSISTENT SNAPSHOT' modifier starts a consistent read for storage engines that are capable of it. This applies only to 'InnoDB'. The effect is the same as issuing a 'START TRANSACTION' followed by a note 'SELECT': select. from any 'InnoDB' table. See note innodb-consistent-read::. The 'WITH CONSISTENT SNAPSHOT' modifier does not change the current transaction isolation level, so it provides a consistent snapshot only if the current isolation level is one that permits a consistent read. The only isolation level that permits a consistent read is 'REPEATABLE READ'. For all other isolation levels, the 'WITH CONSISTENT SNAPSHOT' clause is ignored. As of MySQL 5.7.2, a warning is generated when the 'WITH CONSISTENT SNAPSHOT' clause is ignored.
The 'READ WRITE' and 'READ ONLY' modifiers set the transaction access mode. They permit or prohibit changes to tables used in the transaction. The 'READ ONLY' restriction prevents the transaction from modifying or locking both transactional and nontransactional tables that are visible to other transactions; the transaction can still modify or lock temporary tables.
MySQL enables extra optimizations for queries on 'InnoDB' tables when the transaction is known to be read-only. Specifying 'READ ONLY' ensures these optimizations are applied in cases where the read-only status cannot be determined automatically. See *note innodb-performance-ro-txn:: for more information.
If no access mode is specified, the default mode applies. Unless the default has been changed, it is read/write. It is not permitted to specify both 'READ WRITE' and 'READ ONLY' in the same statement.
In read-only mode, it remains possible to change tables created with the 'TEMPORARY' keyword using DML statements. Changes made with DDL statements are not permitted, just as with permanent tables.
For additional information about transaction access mode, including ways to change the default mode, see *note set-transaction::.
If the 'read_only' system variable is enabled, explicitly starting a transaction with 'START TRANSACTION READ WRITE' requires the 'SUPER' privilege.
Important:
Many APIs used for writing MySQL client applications (such as JDBC) provide their own methods for starting transactions that can (and sometimes should) be used instead of sending a 'START TRANSACTION' statement from the client. See *note connectors-apis::, or the documentation for your API, for more information.
To disable autocommit mode explicitly, use the following statement:
SET autocommit=0;
After disabling autocommit mode by setting the 'autocommit' variable to zero, changes to transaction-safe tables (such as those for note 'InnoDB': innodb-storage-engine. or note 'NDB': mysql-cluster.) are not made permanent immediately. You must use *note 'COMMIT': commit. to store your changes to disk or 'ROLLBACK' to ignore the changes.
'autocommit' is a session variable and must be set for each session. To disable autocommit mode for each new connection, see the description of the 'autocommit' system variable at *note server-system-variables::.
'BEGIN' and 'BEGIN WORK' are supported as aliases of 'START TRANSACTION' for initiating a transaction. 'START TRANSACTION' is standard SQL syntax, is the recommended way to start an ad-hoc transaction, and permits modifiers that 'BEGIN' does not.
The 'BEGIN' statement differs from the use of the 'BEGIN' keyword that starts a note 'BEGIN ... END': begin-end. compound statement. The latter does not begin a transaction. See note begin-end::.
Note:
Within all stored programs (stored procedures and functions, triggers, and events), the parser treats 'BEGIN [WORK]' as the beginning of a note 'BEGIN ... END': begin-end. block. Begin a transaction in this context with note 'START TRANSACTION': commit. instead.
The optional 'WORK' keyword is supported for 'COMMIT' and 'ROLLBACK', as are the 'CHAIN' and 'RELEASE' clauses. 'CHAIN' and 'RELEASE' can be used for additional control over transaction completion. The value of the 'completion_type' system variable determines the default completion behavior. See *note server-system-variables::.
The 'AND CHAIN' clause causes a new transaction to begin as soon as the current one ends, and the new transaction has the same isolation level as the just-terminated transaction. The new transaction also uses the same access mode ('READ WRITE' or 'READ ONLY') as the just-terminated transaction. The 'RELEASE' clause causes the server to disconnect the current client session after terminating the current transaction. Including the 'NO' keyword suppresses 'CHAIN' or 'RELEASE' completion, which can be useful if the 'completion_type' system variable is set to cause chaining or release completion by default.
Beginning a transaction causes any pending transaction to be committed. See *note implicit-commit::, for more information.
Beginning a transaction also causes table locks acquired with note 'LOCK TABLES': lock-tables. to be released, as though you had executed note 'UNLOCK TABLES': lock-tables. Beginning a transaction does not release a global read lock acquired with 'FLUSH TABLES WITH READ LOCK'.
For best results, transactions should be performed using only tables managed by a single transaction-safe storage engine. Otherwise, the following problems can occur:
If you use tables from more than one transaction-safe storage engine (such as 'InnoDB'), and the transaction isolation level is not 'SERIALIZABLE', it is possible that when one transaction commits, another ongoing transaction that uses the same tables sees only some of the changes made by the first transaction. That is, the atomicity of transactions is not guaranteed with mixed engines and inconsistencies can result. (If mixed-engine transactions are infrequent, you can use *note 'SET TRANSACTION ISOLATION LEVEL': set-transaction. to set the isolation level to 'SERIALIZABLE' on a per-transaction basis as necessary.)
If you use tables that are not transaction-safe within a transaction, changes to those tables are stored at once, regardless of the status of autocommit mode.
If you issue a *note 'ROLLBACK': commit. statement after updating a nontransactional table within a transaction, an 'ER_WARNING_NOT_COMPLETE_ROLLBACK' (https://dev.mysql.com/doc/mysql-errors/5.7/en/server-error-reference.html#error_er_warning_not_complete_rollback) warning occurs. Changes to transaction-safe tables are rolled back, but not changes to nontransaction-safe tables.
Each transaction is stored in the binary log in one chunk, upon note 'COMMIT': commit. Transactions that are rolled back are not logged. (Exception: Modifications to nontransactional tables cannot be rolled back. If a transaction that is rolled back includes modifications to nontransactional tables, the entire transaction is logged with a note 'ROLLBACK': commit. statement at the end to ensure that modifications to the nontransactional tables are replicated.) See *note binary-log::.
You can change the isolation level or access mode for transactions with the note 'SET TRANSACTION': set-transaction. statement. See note set-transaction::.
Rolling back can be a slow operation that may occur implicitly without the user having explicitly asked for it (for example, when an error occurs). Because of this, note 'SHOW PROCESSLIST': show-processlist. displays 'Rolling back' in the 'State' column for the session, not only for explicit rollbacks performed with the note 'ROLLBACK': commit. statement but also for implicit rollbacks.
Note:
In MySQL 5.7, 'BEGIN', 'COMMIT', and 'ROLLBACK' are not affected by '--replicate-do-db' or '--replicate-ignore-db' rules.
When 'InnoDB' performs a complete rollback of a transaction, all locks set by the transaction are released. If a single SQL statement within a transaction rolls back as a result of an error, such as a duplicate key error, locks set by the statement are preserved while the transaction remains active. This happens because 'InnoDB' stores row locks in a format such that it cannot know afterward which lock was set by which statement.
If a note 'SELECT': select. statement within a transaction calls a stored function, and a statement within the stored function fails, that statement rolls back. If note 'ROLLBACK': commit. is executed for the transaction subsequently, the entire transaction rolls back.
File: manual.info.tmp, Node: cannot-roll-back, Next: implicit-commit, Prev: commit, Up: sql-transactional-statements
Some statements cannot be rolled back. In general, these include data definition language (DDL) statements, such as those that create or drop databases, those that create, drop, or alter tables or stored routines.
You should design your transactions not to include such statements. If you issue a statement early in a transaction that cannot be rolled back, and then another statement later fails, the full effect of the transaction cannot be rolled back in such cases by issuing a *note 'ROLLBACK': commit. statement.
File: manual.info.tmp, Node: implicit-commit, Next: savepoint, Prev: cannot-roll-back, Up: sql-transactional-statements
The statements listed in this section (and any synonyms for them) implicitly end any transaction active in the current session, as if you had done a *note 'COMMIT': commit. before executing the statement.
Most of these statements also cause an implicit commit after executing. The intent is to handle each such statement in its own special transaction because it cannot be rolled back anyway. Transaction-control and locking statements are exceptions: If an implicit commit occurs before execution, another does not occur after.
Data definition language (DDL) statements that define or modify database objects. note 'ALTER DATABASE ... UPGRADE DATA DIRECTORY NAME': alter-database, note 'ALTER EVENT': alter-event, note 'ALTER PROCEDURE': alter-procedure, note 'ALTER SERVER': alter-server, note 'ALTER TABLE': alter-table, note 'ALTER TABLESPACE': alter-tablespace, note 'ALTER VIEW': alter-view, note 'CREATE DATABASE': create-database, note 'CREATE EVENT': create-event, note 'CREATE INDEX': create-index, note 'CREATE PROCEDURE': create-procedure, note 'CREATE SERVER': create-server, note 'CREATE TABLE': create-table, note 'CREATE TABLESPACE': create-tablespace, note 'CREATE TRIGGER': create-trigger, note 'CREATE VIEW': create-view, note 'DROP DATABASE': drop-database, note 'DROP EVENT': drop-event, note 'DROP INDEX': drop-index, note 'DROP PROCEDURE': drop-procedure, note 'DROP SERVER': drop-server, note 'DROP TABLE': drop-table, note 'DROP TABLESPACE': drop-tablespace, note 'DROP TRIGGER': drop-trigger, note 'DROP VIEW': drop-view, note 'INSTALL PLUGIN': install-plugin, note 'RENAME TABLE': rename-table, note 'TRUNCATE TABLE': truncate-table, *note 'UNINSTALL PLUGIN': uninstall-plugin.
note 'ALTER FUNCTION': alter-function, note 'CREATE FUNCTION': create-function. and note 'DROP FUNCTION': drop-function. also cause an implicit commit when used with stored functions, but not with loadable functions. (note 'ALTER FUNCTION': alter-function. can only be used with stored functions.)
note 'CREATE TABLE': create-table. and note 'DROP TABLE': drop-table. statements do not commit a transaction if the 'TEMPORARY' keyword is used. (This does not apply to other operations on temporary tables such as note 'ALTER TABLE': alter-table. and note 'CREATE INDEX': create-index, which do cause a commit.) However, although no implicit commit occurs, neither can the statement be rolled back, which means that the use of such statements causes transactional atomicity to be violated. For example, if you use *note 'CREATE TEMPORARY TABLE': create-table. and then roll back the transaction, the table remains in existence.
The note 'CREATE TABLE': create-table. statement in 'InnoDB' is processed as a single transaction. This means that a note 'ROLLBACK': commit. from the user does not undo *note 'CREATE TABLE': create-table. statements the user made during that transaction.
*note 'CREATE TABLE ... SELECT': create-table. causes an implicit commit before and after the statement is executed when you are creating nontemporary tables. (No commit occurs for 'CREATE TEMPORARY TABLE ... SELECT'.)
Statements that implicitly use or modify tables in the 'mysql' database. note 'ALTER USER': alter-user, note 'CREATE USER': create-user, note 'DROP USER': drop-user, note 'GRANT': grant, note 'RENAME USER': rename-user, note 'REVOKE': revoke, *note 'SET PASSWORD': set-password.
Transaction-control and locking statements. note 'BEGIN': commit, note 'LOCK TABLES': lock-tables, 'SET autocommit = 1' (if the value is not already 1), note 'START TRANSACTION': commit, note 'UNLOCK TABLES': lock-tables.
note 'UNLOCK TABLES': lock-tables. commits a transaction only if any tables currently have been locked with note 'LOCK TABLES': lock-tables. to acquire nontransactional table locks. A commit does not occur for *note 'UNLOCK TABLES': lock-tables. following 'FLUSH TABLES WITH READ LOCK' because the latter statement does not acquire table-level locks.
Transactions cannot be nested. This is a consequence of the implicit commit performed for any current transaction when you issue a *note 'START TRANSACTION': commit. statement or one of its synonyms.
Statements that cause an implicit commit cannot be used in an XA transaction while the transaction is in an 'ACTIVE' state.
The note 'BEGIN': commit. statement differs from the use of the 'BEGIN' keyword that starts a note 'BEGIN ... END': begin-end. compound statement. The latter does not cause an implicit commit. See *note begin-end::.
Data loading statements. note 'LOAD DATA': load-data. note 'LOAD DATA': load-data. causes an implicit commit only for tables using the *note 'NDB': mysql-cluster. storage engine.
Administrative statements. note 'ANALYZE TABLE': analyze-table, note 'CACHE INDEX': cache-index, note 'CHECK TABLE': check-table, note 'FLUSH': flush, note 'LOAD INDEX INTO CACHE': load-index, note 'OPTIMIZE TABLE': optimize-table, note 'REPAIR TABLE': repair-table, note 'RESET': reset.
Replication control statements. note 'START SLAVE': start-slave, note 'STOP SLAVE': stop-slave, note 'RESET SLAVE': reset-slave, note 'CHANGE MASTER TO': change-master-to.
File: manual.info.tmp, Node: savepoint, Next: lock-tables, Prev: implicit-commit, Up: sql-transactional-statements
SAVEPOINT IDENTIFIER
ROLLBACK [WORK] TO [SAVEPOINT] IDENTIFIER
RELEASE SAVEPOINT IDENTIFIER
'InnoDB' supports the SQL statements note 'SAVEPOINT': savepoint, note 'ROLLBACK TO SAVEPOINT': savepoint, note 'RELEASE SAVEPOINT': savepoint. and the optional 'WORK' keyword for note 'ROLLBACK': commit.
The *note 'SAVEPOINT': savepoint. statement sets a named transaction savepoint with a name of IDENTIFIER. If the current transaction has a savepoint with the same name, the old savepoint is deleted and a new one is set.
The *note 'ROLLBACK TO SAVEPOINT': savepoint. statement rolls back a transaction to the named savepoint without terminating the transaction. Modifications that the current transaction made to rows after the savepoint was set are undone in the rollback, but 'InnoDB' does not release the row locks that were stored in memory after the savepoint. (For a new inserted row, the lock information is carried by the transaction ID stored in the row; the lock is not separately stored in memory. In this case, the row lock is released in the undo.) Savepoints that were set at a later time than the named savepoint are deleted.
If the *note 'ROLLBACK TO SAVEPOINT': savepoint. statement returns the following error, it means that no savepoint with the specified name exists:
ERROR 1305 (42000): SAVEPOINT IDENTIFIER does not exist
The *note 'RELEASE SAVEPOINT': savepoint. statement removes the named savepoint from the set of savepoints of the current transaction. No commit or rollback occurs. It is an error if the savepoint does not exist.
All savepoints of the current transaction are deleted if you execute a note 'COMMIT': commit, or a note 'ROLLBACK': commit. that does not name a savepoint.
A new savepoint level is created when a stored function is invoked or a trigger is activated. The savepoints on previous levels become unavailable and thus do not conflict with savepoints on the new level. When the function or trigger terminates, any savepoints it created are released and the previous savepoint level is restored.
File: manual.info.tmp, Node: lock-tables, Next: set-transaction, Prev: savepoint, Up: sql-transactional-statements
LOCK {TABLE | TABLES}
TBL_NAME [[AS] ALIAS] LOCK_TYPE
[, TBL_NAME [[AS] ALIAS] LOCK_TYPE] ...
LOCK_TYPE: {
READ [LOCAL]
| [LOW_PRIORITY] WRITE
}
UNLOCK {TABLE | TABLES}
MySQL enables client sessions to acquire table locks explicitly for the purpose of cooperating with other sessions for access to tables, or to prevent other sessions from modifying tables during periods when a session requires exclusive access to them. A session can acquire or release locks only for itself. One session cannot acquire locks for another session or release locks held by another session.
Locks may be used to emulate transactions or to get more speed when updating tables. This is explained in more detail in *note lock-tables-restrictions::.
*note 'LOCK TABLES': lock-tables. explicitly acquires table locks for the current client session. Table locks can be acquired for base tables or views. You must have the 'LOCK TABLES' privilege, and the 'SELECT' privilege for each object to be locked.
For view locking, note 'LOCK TABLES': lock-tables. adds all base tables used in the view to the set of tables to be locked and locks them automatically. As of MySQL 5.7.32, note 'LOCK TABLES': lock-tables. checks that the view definer has the proper privileges on the tables underlying the view.
If you lock a table explicitly with note 'LOCK TABLES': lock-tables, any tables used in triggers are also locked implicitly, as described in note lock-tables-and-triggers::.
note 'UNLOCK TABLES': lock-tables. explicitly releases any table locks held by the current session. note 'LOCK TABLES': lock-tables. implicitly releases any table locks held by the current session before acquiring new locks.
Another use for note 'UNLOCK TABLES': lock-tables. is to release the global read lock acquired with the 'FLUSH TABLES WITH READ LOCK' statement, which enables you to lock all tables in all databases. See note flush::. (This is a very convenient way to get backups if you have a file system such as Veritas that can take snapshots in time.)
'LOCK TABLE' is a synonym for 'LOCK TABLES'; 'UNLOCK TABLE' is a synonym for 'UNLOCK TABLES'.
A table lock protects only against inappropriate reads or writes by other sessions. A session holding a 'WRITE' lock can perform table-level operations such as note 'DROP TABLE': drop-table. or note 'TRUNCATE TABLE': truncate-table. For sessions holding a 'READ' lock, note 'DROP TABLE': drop-table. and note 'TRUNCATE TABLE': truncate-table. operations are not permitted.
The following discussion applies only to non-'TEMPORARY' tables. *note 'LOCK TABLES': lock-tables. is permitted (but ignored) for a 'TEMPORARY' table. The table can be accessed freely by the session within which it was created, regardless of what other locking may be in effect. No lock is necessary because no other session can see the table.
*note table-lock-acquisition::
*note table-lock-release::
*note lock-tables-and-transactions::
*note lock-tables-and-triggers::
*note lock-tables-restrictions::
Table Lock Acquisition
To acquire table locks within the current session, use the note 'LOCK TABLES': lock-tables. statement, which acquires metadata locks (see note metadata-locking::).
The following lock types are available:
'READ [LOCAL]' lock:
The session that holds the lock can read the table (but not write it).
Multiple sessions can acquire a 'READ' lock for the table at the same time.
Other sessions can read the table without explicitly acquiring a 'READ' lock.
The 'LOCAL' modifier enables nonconflicting note 'INSERT': insert. statements (concurrent inserts) by other sessions to execute while the lock is held. (See note concurrent-inserts::.) However, 'READ LOCAL' cannot be used if you are going to manipulate the database using processes external to the server while you hold the lock. For 'InnoDB' tables, 'READ LOCAL' is the same as 'READ'.
'[LOW_PRIORITY] WRITE' lock:
The session that holds the lock can read and write the table.
Only the session that holds the lock can access the table. No other session can access it until the lock is released.
Lock requests for the table by other sessions block while the 'WRITE' lock is held.
The 'LOW_PRIORITY' modifier has no effect. In previous versions of MySQL, it affected locking behavior, but this is no longer true. It is now deprecated and its use produces a warning. Use 'WRITE' without 'LOW_PRIORITY' instead.
'WRITE' locks normally have higher priority than 'READ' locks to ensure that updates are processed as soon as possible. This means that if one session obtains a 'READ' lock and then another session requests a 'WRITE' lock, subsequent 'READ' lock requests wait until the session that requested the 'WRITE' lock has obtained the lock and released it. (An exception to this policy can occur for small values of the 'max_write_lock_count' system variable; see *note metadata-locking::.)
If the *note 'LOCK TABLES': lock-tables. statement must wait due to locks held by other sessions on any of the tables, it blocks until all locks can be acquired.
A session that requires locks must acquire all the locks that it needs in a single note 'LOCK TABLES': lock-tables. statement. While the locks thus obtained are held, the session can access only the locked tables. For example, in the following sequence of statements, an error occurs for the attempt to access 't2' because it was not locked in the note 'LOCK TABLES': lock-tables. statement:
mysql> LOCK TABLES t1 READ;
mysql> SELECT COUNT(*) FROM t1;
+----------+
| COUNT(*) |
+----------+
| 3 |
+----------+
mysql> SELECT COUNT(*) FROM t2;
ERROR 1100 (HY000): Table 't2' was not locked with LOCK TABLES
Tables in the 'INFORMATION_SCHEMA' database are an exception. They can be accessed without being locked explicitly even while a session holds table locks obtained with *note 'LOCK TABLES': lock-tables.
You cannot refer to a locked table multiple times in a single query using the same name. Use aliases instead, and obtain a separate lock for the table and each alias:
mysql> LOCK TABLE t WRITE, t AS t1 READ;
mysql> INSERT INTO t SELECT * FROM t;
ERROR 1100: Table 't' was not locked with LOCK TABLES
mysql> INSERT INTO t SELECT * FROM t AS t1;
The error occurs for the first note 'INSERT': insert. because there are two references to the same name for a locked table. The second note 'INSERT': insert. succeeds because the references to the table use different names.
If your statements refer to a table by means of an alias, you must lock the table using that same alias. It does not work to lock the table without specifying the alias:
mysql> LOCK TABLE t READ;
mysql> SELECT * FROM t AS myalias;
ERROR 1100: Table 'myalias' was not locked with LOCK TABLES
Conversely, if you lock a table using an alias, you must refer to it in your statements using that alias:
mysql> LOCK TABLE t AS myalias READ;
mysql> SELECT * FROM t;
ERROR 1100: Table 't' was not locked with LOCK TABLES
mysql> SELECT * FROM t AS myalias;
Note:
'LOCK TABLES' or 'UNLOCK TABLES', when applied to a partitioned table, always locks or unlocks the entire table; these statements do not support partition lock pruning. See *note partitioning-limitations-locking::.
Table Lock Release
When the table locks held by a session are released, they are all released at the same time. A session can release its locks explicitly, or locks may be released implicitly under certain conditions.
A session can release its locks explicitly with *note 'UNLOCK TABLES': lock-tables.
If a session issues a *note 'LOCK TABLES': lock-tables. statement to acquire a lock while already holding locks, its existing locks are released implicitly before the new locks are granted.
If a session begins a transaction (for example, with note 'START TRANSACTION': commit.), an implicit note 'UNLOCK TABLES': lock-tables. is performed, which causes existing locks to be released. (For additional information about the interaction between table locking and transactions, see *note lock-tables-and-transactions::.)
If the connection for a client session terminates, whether normally or abnormally, the server implicitly releases all table locks held by the session (transactional and nontransactional). If the client reconnects, the locks are longer in effect. In addition, if the client had an active transaction, the server rolls back the transaction upon disconnect, and if reconnect occurs, the new session begins with autocommit enabled. For this reason, clients may wish to disable auto-reconnect. With auto-reconnect in effect, the client is not notified if reconnect occurs but any table locks or current transactions are lost. With auto-reconnect disabled, if the connection drops, an error occurs for the next statement issued. The client can detect the error and take appropriate action such as reacquiring the locks or redoing the transaction. See Automatic Reconnection Control (https://dev.mysql.com/doc/c-api/5.7/en/c-api-auto-reconnect.html).
Note:
If you use note 'ALTER TABLE': alter-table. on a locked table, it may become unlocked. For example, if you attempt a second note 'ALTER TABLE': alter-table. operation, the result may be an error 'Table 'TBL_NAME' was not locked with LOCK TABLES'. To handle this, lock the table again prior to the second alteration. See also *note alter-table-problems::.
Interaction of Table Locking and Transactions
note 'LOCK TABLES': lock-tables. and note 'UNLOCK TABLES': lock-tables. interact with the use of transactions as follows:
*note 'LOCK TABLES': lock-tables. is not transaction-safe and implicitly commits any active transaction before attempting to lock the tables.
note 'UNLOCK TABLES': lock-tables. implicitly commits any active transaction, but only if note 'LOCK TABLES': lock-tables. has been used to acquire table locks. For example, in the following set of statements, *note 'UNLOCK TABLES': lock-tables. releases the global read lock but does not commit the transaction because no table locks are in effect:
FLUSH TABLES WITH READ LOCK;
START TRANSACTION;
SELECT ... ;
UNLOCK TABLES;
Beginning a transaction (for example, with *note 'START TRANSACTION': commit.) implicitly commits any current transaction and releases existing table locks.
'FLUSH TABLES WITH READ LOCK' acquires a global read lock and not table locks, so it is not subject to the same behavior as note 'LOCK TABLES': lock-tables. and note 'UNLOCK TABLES': lock-tables. with respect to table locking and implicit commits. For example, note 'START TRANSACTION': commit. does not release the global read lock. See note flush::.
Other statements that implicitly cause transactions to be committed do not release existing table locks. For a list of such statements, see *note implicit-commit::.
The correct way to use note 'LOCK TABLES': lock-tables. and note 'UNLOCK TABLES': lock-tables. with transactional tables, such as 'InnoDB' tables, is to begin a transaction with 'SET autocommit = 0' (not note 'START TRANSACTION': commit.) followed by note 'LOCK TABLES': lock-tables, and to not call *note 'UNLOCK TABLES': lock-tables. until you commit the transaction explicitly. For example, if you need to write to table 't1' and read from table 't2', you can do this:
SET autocommit=0;
LOCK TABLES t1 WRITE, t2 READ, ...;
... DO SOMETHING WITH TABLES T1 AND T2 HERE ...
COMMIT;
UNLOCK TABLES;
When you call note 'LOCK TABLES': lock-tables, 'InnoDB' internally takes its own table lock, and MySQL takes its own table lock. 'InnoDB' releases its internal table lock at the next commit, but for MySQL to release its table lock, you have to call note 'UNLOCK TABLES': lock-tables. You should not have 'autocommit = 1', because then 'InnoDB' releases its internal table lock immediately after the call of *note 'LOCK TABLES': lock-tables, and deadlocks can very easily happen. 'InnoDB' does not acquire the internal table lock at all if 'autocommit = 1', to help old applications avoid unnecessary deadlocks.
*note 'ROLLBACK': commit. does not release table locks.
LOCK TABLES and Triggers
If you lock a table explicitly with *note 'LOCK TABLES': lock-tables, any tables used in triggers are also locked implicitly:
The locks are taken as the same time as those acquired explicitly with the *note 'LOCK TABLES': lock-tables. statement.
The lock on a table used in a trigger depends on whether the table is used only for reading. If so, a read lock suffices. Otherwise, a write lock is used.
If a table is locked explicitly for reading with *note 'LOCK TABLES': lock-tables, but needs to be locked for writing because it might be modified within a trigger, a write lock is taken rather than a read lock. (That is, an implicit write lock needed due to the table's appearance within a trigger causes an explicit read lock request for the table to be converted to a write lock request.)
Suppose that you lock two tables, 't1' and 't2', using this statement:
LOCK TABLES t1 WRITE, t2 READ;
If 't1' or 't2' have any triggers, tables used within the triggers are also locked. Suppose that 't1' has a trigger defined like this:
CREATE TRIGGER t1_a_ins AFTER INSERT ON t1 FOR EACH ROW
BEGIN
UPDATE t4 SET count = count+1
WHERE id = NEW.id AND EXISTS (SELECT a FROM t3);
INSERT INTO t2 VALUES(1, 2);
END;
The result of the *note 'LOCK TABLES': lock-tables. statement is that 't1' and 't2' are locked because they appear in the statement, and 't3' and 't4' are locked because they are used within the trigger:
't1' is locked for writing per the 'WRITE' lock request.
't2' is locked for writing, even though the request is for a 'READ' lock. This occurs because 't2' is inserted into within the trigger, so the 'READ' request is converted to a 'WRITE' request.
't3' is locked for reading because it is only read from within the trigger.
't4' is locked for writing because it might be updated within the trigger.
Table-Locking Restrictions and Conditions
You can safely use note 'KILL': kill. to terminate a session that is waiting for a table lock. See note kill::.
note 'LOCK TABLES': lock-tables. and note 'UNLOCK TABLES': lock-tables. cannot be used within stored programs.
Tables in the 'performance_schema' database cannot be locked with *note 'LOCK TABLES': lock-tables, except the 'setup_XXX' tables.
The scope of a lock generated by 'LOCK TABLES' is a single MySQL server. It is not compatible with NDB Cluster, which has no way of enforcing an SQL-level lock across multiple instances of note 'mysqld': mysqld. You can enforce locking in an API application instead. See note mysql-cluster-limitations-multiple-nodes::, for more information.
The following statements are prohibited while a note 'LOCK TABLES': lock-tables. statement is in effect: note 'CREATE TABLE': create-table, note 'CREATE TABLE ... LIKE': create-table, note 'CREATE VIEW': create-view, *note 'DROP VIEW': drop-view, and DDL statements on stored functions and procedures and events.
For some operations, system tables in the 'mysql' database must be accessed. For example, the *note 'HELP': help. statement requires the contents of the server-side help tables, and 'CONVERT_TZ()' might need to read the time zone tables. The server implicitly locks the system tables for reading as necessary so that you need not lock them explicitly. These tables are treated as just described:
mysql.help_category
mysql.help_keyword
mysql.help_relation
mysql.help_topic
mysql.proc
mysql.time_zone
mysql.time_zone_leap_second
mysql.time_zone_name
mysql.time_zone_transition
mysql.time_zone_transition_type
If you want to explicitly place a 'WRITE' lock on any of those tables with a *note 'LOCK TABLES': lock-tables. statement, the table must be the only one locked; no other table can be locked with the same statement.
Normally, you do not need to lock tables, because all single *note 'UPDATE': update. statements are atomic; no other session can interfere with any other currently executing SQL statement. However, there are a few cases when locking tables may provide an advantage:
If you are going to run many operations on a set of 'MyISAM' tables, it is much faster to lock the tables you are going to use. Locking 'MyISAM' tables speeds up inserting, updating, or deleting on them because MySQL does not flush the key cache for the locked tables until *note 'UNLOCK TABLES': lock-tables. is called. Normally, the key cache is flushed after each SQL statement.
The downside to locking the tables is that no session can update a 'READ'-locked table (including the one holding the lock) and no session can access a 'WRITE'-locked table other than the one holding the lock.
If you are using tables for a nontransactional storage engine, you must use note 'LOCK TABLES': lock-tables. if you want to ensure that no other session modifies the tables between a note 'SELECT': select. and an note 'UPDATE': update. The example shown here requires note 'LOCK TABLES': lock-tables. to execute safely:
LOCK TABLES trans READ, customer WRITE;
SELECT SUM(value) FROM trans WHERE customer_id=SOME_ID;
UPDATE customer
SET total_value=SUM_FROM_PREVIOUS_STATEMENT
WHERE customer_id=SOME_ID;
UNLOCK TABLES;
Without note 'LOCK TABLES': lock-tables, it is possible that another session might insert a new row in the 'trans' table between execution of the note 'SELECT': select. and *note 'UPDATE': update. statements.
You can avoid using *note 'LOCK TABLES': lock-tables. in many cases by using relative updates ('UPDATE customer SET VALUE=VALUE+NEW_VALUE') or the 'LAST_INSERT_ID()' function.
You can also avoid locking tables in some cases by using the user-level advisory lock functions 'GET_LOCK()' and 'RELEASE_LOCK()'. These locks are saved in a hash table in the server and implemented with 'pthread_mutex_lock()' and 'pthread_mutex_unlock()' for high speed. See *note locking-functions::.
See *note internal-locking::, for more information on locking policy.
File: manual.info.tmp, Node: set-transaction, Next: xa, Prev: lock-tables, Up: sql-transactional-statements
SET [GLOBAL | SESSION] TRANSACTION
TRANSACTION_CHARACTERISTIC [, TRANSACTION_CHARACTERISTIC] ...
TRANSACTION_CHARACTERISTIC: {
ISOLATION LEVEL LEVEL
| ACCESS_MODE
}
LEVEL: {
REPEATABLE READ
| READ COMMITTED
| READ UNCOMMITTED
| SERIALIZABLE
}
ACCESS_MODE: {
READ WRITE
| READ ONLY
}
This statement specifies transaction characteristics. It takes a list of one or more characteristic values separated by commas. Each characteristic value sets the transaction isolation level or access mode. The isolation level is used for operations on *note 'InnoDB': innodb-storage-engine. tables. The access mode specifies whether transactions operate in read/write or read-only mode.
In addition, *note 'SET TRANSACTION': set-transaction. can include an optional 'GLOBAL' or 'SESSION' keyword to indicate the scope of the statement.
*note set-transaction-isolation-level::
*note set-transaction-access-mode::
*note set-transaction-scope::
Transaction Isolation Levels
To set the transaction isolation level, use an 'ISOLATION LEVEL LEVEL' clause. It is not permitted to specify multiple 'ISOLATION LEVEL' clauses in the same *note 'SET TRANSACTION': set-transaction. statement.
The default isolation level is 'REPEATABLE READ'. Other permitted values are 'READ COMMITTED', 'READ UNCOMMITTED', and 'SERIALIZABLE'. For information about these isolation levels, see *note innodb-transaction-isolation-levels::.
Transaction Access Mode
To set the transaction access mode, use a 'READ WRITE' or 'READ ONLY' clause. It is not permitted to specify multiple access-mode clauses in the same *note 'SET TRANSACTION': set-transaction. statement.
By default, a transaction takes place in read/write mode, with both reads and writes permitted to tables used in the transaction. This mode may be specified explicitly using *note 'SET TRANSACTION': set-transaction. with an access mode of 'READ WRITE'.
If the transaction access mode is set to 'READ ONLY', changes to tables are prohibited. This may enable storage engines to make performance improvements that are possible when writes are not permitted.
In read-only mode, it remains possible to change tables created with the 'TEMPORARY' keyword using DML statements. Changes made with DDL statements are not permitted, just as with permanent tables.
The 'READ WRITE' and 'READ ONLY' access modes also may be specified for an individual transaction using the *note 'START TRANSACTION': commit. statement.
Transaction Characteristic Scope
You can set transaction characteristics globally, for the current session, or for the next transaction only:
With the 'GLOBAL' keyword:
* The statement applies globally for all subsequent sessions.
* Existing sessions are unaffected.
With the 'SESSION' keyword:
* The statement applies to all subsequent transactions performed
within the current session.
* The statement is permitted within transactions, but does not
affect the current ongoing transaction.
* If executed between transactions, the statement overrides any
preceding statement that sets the next-transaction value of
the named characteristics.
Without any 'SESSION' or 'GLOBAL' keyword:
* The statement applies only to the next single transaction
performed within the session.
* Subsequent transactions revert to using the session value of
the named characteristics.
* The statement is not permitted within transactions:
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.02 sec)
mysql> SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
ERROR 1568 (25001): Transaction characteristics can't be changed
while a transaction is in progress
A change to global transaction characteristics requires the 'SUPER' privilege. Any session is free to change its session characteristics (even in the middle of a transaction), or the characteristics for its next transaction (prior to the start of that transaction).
To set the global isolation level at server startup, use the '--transaction-isolation=LEVEL' option on the command line or in an option file. Values of LEVEL for this option use dashes rather than spaces, so the permissible values are 'READ-UNCOMMITTED', 'READ-COMMITTED', 'REPEATABLE-READ', or 'SERIALIZABLE'.
Similarly, to set the global transaction access mode at server startup, use the '--transaction-read-only' option. The default is 'OFF' (read/write mode) but the value can be set to 'ON' for a mode of read only.
For example, to set the isolation level to 'REPEATABLE READ' and the access mode to 'READ WRITE', use these lines in the '[mysqld]' section of an option file:
[mysqld]
transaction-isolation = REPEATABLE-READ
transaction-read-only = OFF
At runtime, characteristics at the global, session, and next-transaction scope levels can be set indirectly using the note 'SET TRANSACTION': set-transaction. statement, as described previously. They can also be set directly using the note 'SET': set-variable. statement to assign values to the 'transaction_isolation' and 'transaction_read_only' system variables:
*note 'SET TRANSACTION': set-transaction. permits optional 'GLOBAL' and 'SESSION' keywords for setting transaction characteristics at different scope levels.
The *note 'SET': set-variable. statement for assigning values to the 'transaction_isolation' and 'transaction_read_only' system variables has syntaxes for setting these variables at different scope levels.
The following tables show the characteristic scope level set by each *note 'SET TRANSACTION': set-transaction. and variable-assignment syntax.
SET TRANSACTION Syntax for Transaction Characteristics
Syntax Affected Characteristic Scope
'SET GLOBAL TRANSACTION Global TRANSACTION_CHARACTERISTIC'
'SET SESSION TRANSACTION Session TRANSACTION_CHARACTERISTIC'
'SET TRANSACTION Next transaction only TRANSACTION_CHARACTERISTIC'
SET Syntax for Transaction Characteristics
Syntax Affected Characteristic Scope
'SET GLOBAL VAR_NAME = VALUE' Global
'SET @@GLOBAL.VAR_NAME = VALUE' Global
'SET SESSION VAR_NAME = VALUE' Session
'SET @@SESSION.VAR_NAME = VALUE' Session
'SET VAR_NAME = VALUE' Session
'SET @@VAR_NAME = VALUE' Next transaction only
It is possible to check the global and session values of transaction characteristics at runtime:
SELECT @@GLOBAL.transaction_isolation, @@GLOBAL.transaction_read_only;
SELECT @@SESSION.transaction_isolation, @@SESSION.transaction_read_only;
Prior to MySQL 5.7.20, use 'tx_isolation' and 'tx_read_only' rather than 'transaction_isolation' and 'transaction_read_only'.
File: manual.info.tmp, Node: xa, Prev: set-transaction, Up: sql-transactional-statements
Menu:
xa-restrictions:: Restrictions on XA Transactions
Support for XA transactions is available for the note 'InnoDB': innodb-storage-engine. storage engine. The MySQL XA implementation is based on the X/Open CAE document 'Distributed Transaction Processing: The XA Specification'. This document is published by The Open Group and available at http://www.opengroup.org/public/pubs/catalog/c193.htm. Limitations of the current XA implementation are described in note xa-restrictions::.
On the client side, there are no special requirements. The XA interface to a MySQL server consists of SQL statements that begin with the 'XA' keyword. MySQL client programs must be able to send SQL statements and to understand the semantics of the XA statement interface. They do not need be linked against a recent client library. Older client libraries also work.
Among the MySQL Connectors, MySQL Connector/J 5.0.0 and higher supports XA directly, by means of a class interface that handles the XA SQL statement interface for you.
XA supports distributed transactions, that is, the ability to permit multiple separate transactional resources to participate in a global transaction. Transactional resources often are RDBMSs but may be other kinds of resources.
A global transaction involves several actions that are transactional in themselves, but that all must either complete successfully as a group, or all be rolled back as a group. In essence, this extends ACID properties 'up a level' so that multiple ACID transactions can be executed in concert as components of a global operation that also has ACID properties. (As with nondistributed transactions, 'SERIALIZABLE' may be preferred if your applications are sensitive to read phenomena. 'REPEATABLE READ' may not be sufficient for distributed transactions.)
Some examples of distributed transactions:
An application may act as an integration tool that combines a messaging service with an RDBMS. The application makes sure that transactions dealing with message sending, retrieval, and processing that also involve a transactional database all happen in a global transaction. You can think of this as 'transactional email.'
An application performs actions that involve different database servers, such as a MySQL server and an Oracle server (or multiple MySQL servers), where actions that involve multiple servers must happen as part of a global transaction, rather than as separate transactions local to each server.
A bank keeps account information in an RDBMS and distributes and receives money through automated teller machines (ATMs). It is necessary to ensure that ATM actions are correctly reflected in the accounts, but this cannot be done with the RDBMS alone. A global transaction manager integrates the ATM and database resources to ensure overall consistency of financial transactions.
Applications that use global transactions involve one or more Resource Managers and a Transaction Manager:
A Resource Manager (RM) provides access to transactional resources. A database server is one kind of resource manager. It must be possible to either commit or roll back transactions managed by the RM.
A Transaction Manager (TM) coordinates the transactions that are part of a global transaction. It communicates with the RMs that handle each of these transactions. The individual transactions within a global transaction are 'branches' of the global transaction. Global transactions and their branches are identified by a naming scheme described later.
The MySQL implementation of XA enables a MySQL server to act as a Resource Manager that handles XA transactions within a global transaction. A client program that connects to the MySQL server acts as the Transaction Manager.
To carry out a global transaction, it is necessary to know which components are involved, and bring each component to a point when it can be committed or rolled back. Depending on what each component reports about its ability to succeed, they must all commit or roll back as an atomic group. That is, either all components must commit, or all components must roll back. To manage a global transaction, it is necessary to take into account that any component or the connecting network might fail.
The process for executing a global transaction uses two-phase commit (2PC). This takes place after the actions performed by the branches of the global transaction have been executed.
In the first phase, all branches are prepared. That is, they are told by the TM to get ready to commit. Typically, this means each RM that manages a branch records the actions for the branch in stable storage. The branches indicate whether they are able to do this, and these results are used for the second phase.
In the second phase, the TM tells the RMs whether to commit or roll back. If all branches indicated when they were prepared that they can commit, all branches are told to commit. If any branch indicated when it was prepared that it could not commit, all branches are told to roll back.
In some cases, a global transaction might use one-phase commit (1PC). For example, when a Transaction Manager finds that a global transaction consists of only one transactional resource (that is, a single branch), that resource can be told to prepare and commit at the same time.
File: manual.info.tmp, Node: xa-statements, Next: xa-states, Prev: xa, Up: xa
13.3.7.1 XA Transaction SQL Statements ......................................
To perform XA transactions in MySQL, use the following statements:
XA {START|BEGIN} XID [JOIN|RESUME]
XA END XID [SUSPEND [FOR MIGRATE]]
XA PREPARE XID
XA COMMIT XID [ONE PHASE]
XA ROLLBACK XID
XA RECOVER [CONVERT XID]
For *note 'XA START': xa-statements, the 'JOIN' and 'RESUME' clauses are recognized but have no effect.
For *note 'XA END': xa-statements. the 'SUSPEND [FOR MIGRATE]' clause is recognized but has no effect.
Each XA statement begins with the 'XA' keyword, and most of them require an XID value. An XID is an XA transaction identifier. It indicates which transaction the statement applies to. XID values are supplied by the client, or generated by the MySQL server. An XID value has from one to three parts:
XID: GTRID [, BQUAL [, FORMATID ]]
GTRID is a global transaction identifier, BQUAL is a branch qualifier, and FORMATID is a number that identifies the format used by the GTRID and BQUAL values. As indicated by the syntax, BQUAL and FORMATID are optional. The default BQUAL value is '''' if not given. The default FORMATID value is 1 if not given.
GTRID and BQUAL must be string literals, each up to 64 bytes (not characters) long. GTRID and BQUAL can be specified in several ways. You can use a quoted string (''ab''), hex string ('X'6162'', '0x6162'), or bit value ('b'NNNN'').
FORMATID is an unsigned integer.
The GTRID and BQUAL values are interpreted in bytes by the MySQL server's underlying XA support routines. However, while an SQL statement containing an XA statement is being parsed, the server works with some specific character set. To be safe, write GTRID and BQUAL as hex strings.
XID values typically are generated by the Transaction Manager. Values generated by one TM must be different from values generated by other TMs. A given TM must be able to recognize its own XID values in a list of values returned by the *note 'XA RECOVER': xa-statements. statement.
note 'XA START XID': xa-statements. starts an XA transaction with the given XID value. Each XA transaction must have a unique XID value, so the value must not currently be used by another XA transaction. Uniqueness is assessed using the GTRID and BQUAL values. All following XA statements for the XA transaction must be specified using the same XID value as that given in the note 'XA START': xa-statements. statement. If you use any of those statements but specify an XID value that does not correspond to some existing XA transaction, an error occurs.
One or more XA transactions can be part of the same global transaction. All XA transactions within a given global transaction must use the same GTRID value in the XID value. For this reason, GTRID values must be globally unique so that there is no ambiguity about which global transaction a given XA transaction is part of. The BQUAL part of the XID value must be different for each XA transaction within a global transaction. (The requirement that BQUAL values be different is a limitation of the current MySQL XA implementation. It is not part of the XA specification.)
The note 'XA RECOVER': xa-statements. statement returns information for those XA transactions on the MySQL server that are in the 'PREPARED' state. (See note xa-states::.) The output includes a row for each such XA transaction on the server, regardless of which client started it.
*note 'XA RECOVER': xa-statements. output rows look like this (for an example XID value consisting of the parts ''abc'', ''def'', and '7'):
mysql> XA RECOVER;
+----------+--------------+--------------+--------+
| formatID | gtrid_length | bqual_length | data |
+----------+--------------+--------------+--------+
| 7 | 3 | 3 | abcdef |
+----------+--------------+--------------+--------+
The output columns have the following meanings:
'formatID' is the FORMATID part of the transaction XID
'gtrid_length' is the length in bytes of the GTRID part of the XID
'bqual_length' is the length in bytes of the BQUAL part of the XID
'data' is the concatenation of the GTRID and BQUAL parts of the XID
XID values may contain nonprintable characters. As of MySQL 5.7.5, *note 'XA RECOVER': xa-statements. permits an optional 'CONVERT XID' clause so that clients can request XID values in hexadecimal.
File: manual.info.tmp, Node: xa-states, Next: xa-restrictions, Prev: xa-statements, Up: xa
13.3.7.2 XA Transaction States ..............................
An XA transaction progresses through the following states:
Use *note 'XA START': xa-statements. to start an XA transaction and put it in the 'ACTIVE' state.
For an 'ACTIVE' XA transaction, issue the SQL statements that make up the transaction, and then issue an note 'XA END': xa-statements. statement. note 'XA END': xa-statements. puts the transaction in the 'IDLE' state.
For an 'IDLE' XA transaction, you can issue either an *note 'XA PREPARE': xa-statements. statement or an 'XA COMMIT ... ONE PHASE' statement:
* *note 'XA PREPARE': xa-statements. puts the transaction in the
'PREPARED' state. An *note 'XA RECOVER': xa-statements.
statement at this point includes the transaction's XID value
in its output, because *note 'XA RECOVER': xa-statements.
lists all XA transactions that are in the 'PREPARED' state.
* 'XA COMMIT ... ONE PHASE' prepares and commits the
transaction. The XID value is not listed by *note 'XA
RECOVER': xa-statements. because the transaction terminates.
For a 'PREPARED' XA transaction, you can issue an note 'XA COMMIT': xa-statements. statement to commit and terminate the transaction, or note 'XA ROLLBACK': xa-statements. to roll back and terminate the transaction.
Here is a simple XA transaction that inserts a row into a table as part of a global transaction:
mysql> XA START 'xatest';
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO mytable (i) VALUES(10);
Query OK, 1 row affected (0.04 sec)
mysql> XA END 'xatest';
Query OK, 0 rows affected (0.00 sec)
mysql> XA PREPARE 'xatest';
Query OK, 0 rows affected (0.00 sec)
mysql> XA COMMIT 'xatest';
Query OK, 0 rows affected (0.00 sec)
Within the context of a given client connection, XA transactions and local (non-XA) transactions are mutually exclusive. For example, if note 'XA START': xa-statements. has been issued to begin an XA transaction, a local transaction cannot be started until the XA transaction has been committed or rolled back. Conversely, if a local transaction has been started with note 'START TRANSACTION': commit, no XA statements can be used until the transaction has been committed or rolled back.
If an XA transaction is in the 'ACTIVE' state, you cannot issue any statements that cause an implicit commit. That would violate the XA contract because you could not roll back the XA transaction. The following error is raised if you try to execute such a statement:
ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed
when global transaction is in the ACTIVE state
Statements to which the preceding remark applies are listed at *note implicit-commit::.
File: manual.info.tmp, Node: xa-restrictions, Prev: xa-states, Up: xa
13.3.7.3 Restrictions on XA Transactions ........................................
XA transaction support is limited to the 'InnoDB' storage engine.
For 'external XA,' a MySQL server acts as a Resource Manager and client programs act as Transaction Managers. For 'Internal XA', storage engines within a MySQL server act as RMs, and the server itself acts as a TM. Internal XA support is limited by the capabilities of individual storage engines. Internal XA is required for handling XA transactions that involve more than one storage engine. The implementation of internal XA requires that a storage engine support two-phase commit at the table handler level, and currently this is true only for 'InnoDB'.
For *note 'XA START': xa-statements, the 'JOIN' and 'RESUME' clauses are recognized but have no effect.
For *note 'XA END': xa-statements. the 'SUSPEND [FOR MIGRATE]' clause is recognized but has no effect.
The requirement that the BQUAL part of the XID value be different for each XA transaction within a global transaction is a limitation of the current MySQL XA implementation. It is not part of the XA specification.
Prior to MySQL 5.7.7, XA transactions were not compatible with replication. This was because an XA transaction that was in 'PREPARED' state would be rolled back on clean server shutdown or client disconnect. Similarly, an XA transaction that was in 'PREPARED' state would still exist in 'PREPARED' state in case the server was shutdown abnormally and then started again, but the contents of the transaction could not be written to the binary log. In both of these situations the XA transaction could not be replicated correctly.
In MySQL 5.7.7 and later, there is a change in behavior and an XA transaction is written to the binary log in two parts. When 'XA PREPARE ' is issued, the first part of the transaction up to 'XA PREPARE' is written using an initial GTID. A 'XA_prepare_log_event' is used to identify such transactions in the binary log. When 'XA COMMIT' or 'XA ROLLBACK' is issued, a second part of the transaction containing only the 'XA COMMIT' or 'XA ROLLBACK' statement is written using a second GTID. Note that the initial part of the transaction, identified by 'XA_prepare_log_event', is not necessarily followed by its 'XA COMMIT' or 'XA ROLLBACK', which can cause interleaved binary logging of any two XA transactions. The two parts of the XA transaction can even appear in different binary log files. This means that an XA transaction in 'PREPARED' state is now persistent until an explicit 'XA COMMIT' or 'XA ROLLBACK' statement is issued, ensuring that XA transactions are compatible with replication.
On a replica, immediately after the XA transaction is prepared, it is detached from the replica applier thread, and can be committed or rolled back by any thread on the replica. This means that the same XA transaction can appear in the note 'events_transactions_current': performance-schema-events-transactions-current-table. table with different states on different threads. The note 'events_transactions_current': performance-schema-events-transactions-current-table. table displays the current status of the most recent monitored transaction event on the thread, and does not update this status when the thread is idle. So the XA transaction can still be displayed in the 'PREPARED' state for the original applier thread, after it has been processed by another thread. To positively identify XA transactions that are still in the 'PREPARED' state and need to be recovered, use the *note 'XA RECOVER': xa-statements. statement rather than the Performance Schema transaction tables.
The following restrictions exist for using XA transactions in MySQL 5.7.7 and later:
XA transactions are not fully resilient to an unexpected halt with respect to the binary log. If there is an unexpected halt while the server is in the middle of executing an 'XA PREPARE', 'XA COMMIT', 'XA ROLLBACK', or 'XA COMMIT ... ONE PHASE' statement, the server might not be able to recover to a correct state, leaving the server and the binary log in an inconsistent state. In this situation, the binary log might either contain extra XA transactions that are not applied, or miss XA transactions that are applied. Also, if GTIDs are enabled, after recovery '@@GLOBAL.GTID_EXECUTED' might not correctly describe the transactions that have been applied. Note that if an unexpected halt occurs before 'XA PREPARE', between 'XA PREPARE' and 'XA COMMIT' (or 'XA ROLLBACK'), or after 'XA COMMIT' (or 'XA ROLLBACK'), the server and binary log are correctly recovered and taken to a consistent state.
The use of replication filters or binary log filters in combination with XA transactions is not supported. Filtering of tables could cause an XA transaction to be empty on a replica, and empty XA transactions are not supported. Also, with the settings 'master_info_repository=TABLE' and 'relay_log_info_repository=TABLE' on a replica, which became the defaults in MySQL 8.0, the internal state of the data engine transaction is changed following a filtered XA transaction, and can become inconsistent with the replication transaction context state.
The error 'ER_XA_REPLICATION_FILTERS' (https://dev.mysql.com/doc/mysql-errors/5.7/en/server-error-reference.html#error_er_xa_replication_filters) is logged whenever an XA transaction is impacted by a replication filter, whether or not the transaction was empty as a result. If the transaction is not empty, the replica is able to continue running, but you should take steps to discontinue the use of replication filters with XA transactions in order to avoid potential issues. If the transaction is empty, the replica stops. In that event, the replica might be in an undetermined state in which the consistency of the replication process might be compromised. In particular, the 'gtid_executed' set on a replica of the replica might be inconsistent with that on the source. To resolve this situation, isolate the source and stop all replication, then check GTID consistency across the replication topology. Undo the XA transaction that generated the error message, then restart replication.
Prior to MySQL 5.7.19, 'FLUSH TABLES WITH READ LOCK' is not compatible with XA transactions.
XA transactions are considered unsafe for statement-based replication. If two XA transactions committed in parallel on the source are being prepared on the replica in the inverse order, locking dependencies can occur that cannot be safely resolved, and it is possible for replication to fail with deadlock on the replica. This situation can occur for a single-threaded or multithreaded replica. When 'binlog_format=STATEMENT' is set, a warning is issued for DML statements inside XA transactions. When 'binlog_format=MIXED' or 'binlog_format=ROW' is set, DML statements inside XA transactions are logged using row-based replication, and the potential issue is not present.
File: manual.info.tmp, Node: sql-replication-statements, Next: sql-prepared-statements, Prev: sql-transactional-statements, Up: sql-statements