How does STRICT_ALL_TABLES work with multi-row statements and partial updates?
-
06-01-2021 - |
题
In the docs for STRICT_ALL_TABLES
it states,
For
STRICT_ALL_TABLES
, MySQL returns an error and ignores the rest of the rows. However, because the earlier rows have been inserted or updated, the result is a partial update. To avoid this, use single-row statements, which can be aborted without changing the table.
What does this mean though?
CREATE TABLE foo ( a int NOT NULL );
INSERT INTO foo VALUES (NULL), (NULL);
This does what everyone would reasonably expect a totally insane database to do,
SELECT * FROM foo;
+---+
| a |
+---+
| 0 |
| 0 |
+---+
2 rows in set (0.00 sec)
But, I expected a multi-row INSERT
to insert the non-violating rows that are seen first,
SET sql_mode='STRICT_ALL_TABLES';
INSERT INTO foo VALUES (5), (NULL);
To insert just one row with 5
, as per the docs in STRICT_ALL_TABLES
. Instead it does,
ERROR 1048 (23000): Column 'a' cannot be null
How do I interpret the docs to STRICT_ALL_TABLES
when they say earlier rows .. partial update and "single-row statements". And why is MySQL doing something less horrible then documented? I'm pleasantly surprised.
解决方案
I agree that the split between _ALL_
and _TRANS_
needs clarification.
Earlier on that page it says
With TRADITIONAL mode enabled, an INSERT or UPDATE aborts as soon as an error occurs. If you are using a nontransactional storage engine, this may not be what you want because data changes made prior to the error may not be rolled back, resulting in a “partially done” update.
I think the meat of the issue is InnoDB versus MyISAM.
MyISAM is covered by STRICT_ALL_TABLES
, but not by STRICT_TRANS_TABLES
. If an UPDATE
or DELETE
is aborted for any reason mid-stream, some rows will have been updated or deleted. You have no practical way to clean up the mess. (This is a major reason never to use MyISAM.)
InnoDB is covered by both settings, but STRICT_TRANS_TABLES
is more relevant, and overrides the statement about "earlier rows". UPDATE
and DELETE
are atomic.
Also involved is the question of aborting with an error versus doing something so you can keep going. For example, bad dates and defaults without an explicit DEFAULT
, etc. These are cases where MySQL (unlike some other engines) defines that a non-abort action will be taken.
If your Question is intended to point out poor phrasing in the documentation, go for it. But do it at bugs.mysql.com , where there is a chance of it getting fixed.
MySQL 8.0 moves toward more robust default settings by changing the defaults.