I have a question about MySQL InnoDB. For example: I have thread A to start a transaction:
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> update user set name = "Jim" where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
And then, I just leave the thread A as it is. I started another thread B to do this:
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> update user set name = "Tom" where id = 1;
And I got the error:
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
It makes sense, because thread A put a 'X' lock on that row.
And then I used thread B to do this:
mysql> start transaction;
Query OK, 0 rows affected (0.01 sec)
mysql> select * from user where id = 1;
+----+------+
| id | name |
+----+------+
| 1 | wlq3 |
+----+------+
1 row in set (0.00 sec)
Here I'm confused. Like I just said thread A put a 'X' lock on that row. why thread B can read this row. In my opinion, reading data need a share lock, but exclusive lock is already on that data. Is there anyone can help me ,thanks!
By the way, the isolation level of thread A is repeatable read, and thread B is read committed.
Well wlq3 is the committed value in the database so transaction B reads this value. The update with Jim has not committed yet.A lock will not block a read it will just block a update this is due to the MVCC locking model which is implemented in InnoDB.
See this link for more information: InnoDB's row locking the same as MVCC Non-Blocking Reads?
Related
MySQL 8.0 Command Line Client is giving me a timeout error and I have restarting the transaction by typing "start transaction" another time. Keep in mind that I have another command line open with the table CIA_DATA.new_table and it is also being updated with the same changes. (I am doing this to follow a tutorial.) Here is the script:
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> update CIA_DATA.new_table set c1 = 2 where c1 = 1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
Updated code for help in Answers Comments:
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> drop table CIA_DATA.new_table;
ERROR 1051 (42S02): Unknown table 'cia_data.new_table'
mysql> create table CIA_DATA.new_table ( c1 int primary key);
Query OK, 0 rows affected (0.08 sec)
mysql> insert into CIA_DATA.new_table values (1);
Query OK, 1 row affected (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.05 sec)
mysql> select * from CIA_DATA.new_table;
+----+
| c1 |
+----+
| 1 |
+----+
1 row in set (0.00 sec)
mysql> update CIA_DATA.new_table set c1 = 2 where c1 = 1;
Query OK, 1 row affected (0.05 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> close transaction
-> \c
mysql> close transaction;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'close transaction' at line 1
mysql> --innodb-lock-wait-timeout=#
-> \c
mysql> --innodb-lock-wait-timeout=#;
->
Thanks,
thecoolgeek
What happen ony your computer:
One transaction locks the table and you didn't release the lock by endind the transaction.
you start a new tansaction and it encounters a lockesd table and waits for the release
As the first transaction and the lock wasn't released, the secnd goes into to timeout.
Locks are in the best case difficult. and sometimes it takes hours or days to solve them.
so close the tranaction as fast as you can, so that the timeout not happen or increase the timeout https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_lock_wait_timeout
I'm working on a financial system and I've got a problem with the MySQL transactions.
The system is a simple stock exchange, where users can buy and sell virtual shares. To keep integrity in buy and sell process I use transactions.
The problem is that in some cases (I don't know what it depends on) some of transactions are rolled back (or not commited), but next queries are processed.
The process is following:
User wants to buy shares for 1000 USD
In orderbook there are 4 offers for 250 USD
START TRANSACTION
For every offer:
Script does a UPDATE query (moving USD from one user to another and shares in the opposite way). Then script INSERTs entries to history tables.
Users pay a fee (UPDATE balances).
Repeat 5 and 6 for the next offer.
COMMIT
Now the key part - in some cases changes from point 5 are not saved, but from the 6 they are (I see that fee was paid, but there is no transaction in the history).
I'm not using ROLLBACK during this transactions and the script is not breaking (because in this case fee wouldn't be paid).
Is there any possibility that transaction is rolling back without ROLLBACK query? Or can MySQL COMMIT only few newest queries instead of all?
Transactions or not, it's the responsibility of your client code to verity that all your INSERT or UPDATE queries complete successfully and then either issue a explicit ROLLBACK or close the connection withour COMMIT to issue an implicity ROLLBACK. If any of them fails but your code goes on, those queries will not take effect (because they failed) but the rest will do.
Here's a simplified example:
mysql> create table test (
-> id int(10) unsigned not null,
-> primary key (id)
-> );
Query OK, 0 rows affected (0.02 sec)
mysql> insert into test(id) values (1);
Query OK, 1 row affected (0.00 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into test(id) values (2);
Query OK, 1 row affected (0.00 sec)
mysql> insert into test(id) values (-3);
ERROR 1264 (22003): Out of range value for column 'id' at row 1
We should have rollbacked and aborted here, but we didn't.
mysql> insert into test(id) values (4);
Query OK, 1 row affected (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from test;
+----+
| id |
+----+
| 1 |
| 2 |
| 4 |
+----+
3 rows in set (0.00 sec)
4 rows expected, got 3.
Other than that, there're many circumstances where you can get an unwanted COMMIT but an unwanted ROLLBACK is something I'm not sure that can happen unless you terminate a session with pending changes.
It's long time since the question was asked, but the problem actually was that I didn't check for the SQL errors for every query.
Actually at some points, when I should rollback transaction, I didn't do it.
If your are looking for answer - check again if you testing ALL queries in your transaction for successful execution and don't trust that the framework you are using is doing it for you automatically (just check it again).
THis example works :
MariaDB [test]> SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Query OK, 0 rows affected (0.00 sec)
MariaDB [test]> INSERT INTO test(id, value) VALUES (1, 'test'), (2, 'test 2');
Query OK, 2 rows affected (0.37 sec)
Records: 2 Duplicates: 0 Warnings: 0
MariaDB [test]> SELECT * FROM test;
+------+--------+
| id | value |
+------+--------+
| 1 | test |
| 2 | test 2 |
+------+--------+
2 rows in set (0.00 sec)
MariaDB [test]> COMMIT;
but when i changed transaction level :
MariaDB [test]> SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
Query OK, 0 rows affected (0.00 sec)
MariaDB [test]> INSERT INTO test(id, value) VALUES (1, 'test'), (2, 'test 2');
ERROR 1665 (HY000): Cannot execute statement: impossible to write to binary log
since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine lim
ited to row-based logging. InnoDB is limited to row-logging when transaction iso
lation level is READ COMMITTED or READ UNCOMMITTED.
MariaDB [test]> SELECT * FROM test;
Empty set (0.00 sec)
MariaDB [test]> COMMIT;
Query OK, 0 rows affected (0.00 sec)
How to fix this problem ?
The error message is quite detailed in this case. According to mysql documentation on binlog_format:
If you are using InnoDB tables and the transaction isolation level is READ COMMITTED or READ UNCOMMITTED, only row-based logging can be used. It is possible to change the logging format to STATEMENT, but doing so at runtime leads very rapidly to errors because InnoDB can no longer perform inserts.
So, you have to set the binlog_format to ROW:
SET SESSION binlog_format = 'ROW';
I'm using InnoDb engine by default. And this is what looks strange:
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> set session transaction isolation level serializable;
Query OK, 0 rows affected (0.00 sec)
mysql> create table test_1(id int);
Query OK, 0 rows affected (0.07 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> show tables;
+------------------+
| Tables_in_reestr |
+------------------+
| test_1 |
+------------------+
1 rows in set (0.00 sec)
It looks strange, because I started transaction and rollbacked, but to no avail. So, what I'm doing wrong?
To expand on the comment above: in MySQL, basically all operations that alter database objects perform auto-commit. The main categories are:
any DDL on your objects, like CREATE/ALTER/DROP TABLE/VIEW/INDEX...,
anything that modifies the system database mysql, like ALTER/CREATE USER,
any administrative commands, like ANALYZE,
any data loading/replication statements.
Actually, I find it best to assume that INSERT, UPDATE and DELETE are safe, and anything else is not.
Source: https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html
I am experiencing some problems with table locking. I have locked certain number of table in transaction. LOCK TABLES t1 READ, t2 READ, t3 READ, t4 READ,t5 READ,t6 READ,t7 READ;
While reading its ok, but when I am trying to write/update to this tables it's showing the error Table 't1' was locked with a READ lock and can't be updated
But I never locked the table for write, I have to write to these tables with updated values.
My aim is I need to select and I need to update rows, while others should not interact with above tables until the process finished.
Much appreciated your solutions!
From mysql doc:
Rules for Lock Acquisition
To acquire table locks within the current session, use the LOCK TABLES statement. The following lock types are available:
READ [LOCAL] lock:
The session that holds the lock can read the table (but not write it).
MariaDB [test]> lock table super1 read;
Query OK, 0 rows affected (0.00 sec)
MariaDB [test]> select * from super1;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 5 |
| 6 |
| 7 |
+----+
6 rows in set (0.00 sec)
MariaDB [test]> insert into super1 VALUE(10);
ERROR 1099 (HY000): Table 'super1' was locked with a READ lock and can't be updted
other session can SELECT too
MariaDB [test]> unlock tables;
Query OK, 0 rows affected (0.00 sec)
MariaDB [test]> lock table super1 write;
Query OK, 0 rows affected (0.00 sec)
other session can't SELECT
MariaDB [test]> insert into super1 VALUE(10);
Query OK, 1 row affected (0.00 sec)
MariaDB [test]> insert into super1 VALUE(11);
Query OK, 1 row affected (0.00 sec)
MariaDB [test]> unlock tables;
Query OK, 0 rows affected (0.00 sec)