以下两条事务发生更新丢失的情况:BEGIN;
SELECT count FROM test;
UPDATE test SET count=1 WHERE count=0;
COMMIT;
当两个事务同时开始时,第一个事务(T1)执行SELECT count FROM test;语句并读取了count的值为0,然后第二个事务(T2)也执行了同样的SELECT语句并读取了count的值为0。接着T1执行了UPDATE test SET count=1 WHERE count=0;,将count的值更新为1并提交事务,然后T2也执行了同样的UPDATE语句并将count的值更新为1并提交事务。这时候,第二个事务覆盖了第一个事务的更新,导致第一个事务的更新丢失。
当两个事务同时开始时,第一个事务(T1)执行SELECT count FROM test;语句并读取了count的值为0,然后第二个事务(T2)也执行了同样的SELECT语句并读取了count的值为0。接着T1执行了UPDATE test SET count=1 WHERE count=0;,将count的值更新为1并提交事务,但是在提交事务之前,T2也执行了UPDATE test SET count=2 WHERE count=0;,将count的值更新为2并提交事务。这时候,第二个事务覆盖了第一个事务的更新,导致第一个事务的更新丢失。
以下两条事务发生更新丢失的情况:BEGIN;
SELECT count FROM test;
UPDATE test SET count=1 WHERE count=0;
COMMIT;BEGIN;
SELECT count FROM test;
UPDATE test SET count=2 WHERE count=0;
COMMIT;
当两个事务同时开始时,第一个事务(T1)执行SELECT count FROM test;语句并读取了count的值为0,然后第二个事务(T2)也执行了同样的SELECT语句并读取了count的值为0。接着T1执行了UPDATE test SET count=1 WHERE count=0;,将count的值更新为1并提交事务,然后T2执行了UPDATE test SET count=2 WHERE count=0;,将count的值更新为2并提交事务。这时候,第二个事务覆盖了第一个事务的更新,导致第一个事务的更新丢失。
但在msql 8.0上的执行结果为1,为什么
MySQL 8.0 引入了可重复读隔离级别下的写入冲突检测,可以防止更新丢失的情况,从而避免了并发事务之间的写入冲突。在可重复读隔离级别下,当一个事务执行 UPDATE 或者 DELETE 语句的时候,MySQL 会对数据行加锁,其他事务不能对这个数据行进行写入,直到这个事务提交或者回滚。因此,当两个事务同时执行 UPDATE 语句时,后执行的事务会因为加锁失败而被阻塞,直到前一个事务提交或者回滚后才能继续执行更新操作。
在你的情况下,第一个事务执行 UPDATE 语句并提交后,第二个事务执行 UPDATE 语句时会因为行锁而被阻塞,直到第一个事务提交后才能继续执行。因此,第二个事务实际上没有修改任何数据,因此查询的结果仍然为1。
mysql5.0下也有此机制吗
在 MySQL 5.0 中,也有锁机制和事务隔离级别的概念,但是 MySQL 5.0 默认的隔离级别是可重复读,而不是读已提交。因此,在 MySQL 5.0 中,如果两个事务同时执行 UPDATE 语句,就可能发生更新丢失的情况。在这种情况下,后执行的事务会覆盖先执行的事务的更新结果。
不过,MySQL 5.0 也提供了行级锁机制,可以通过显式地使用 SELECT ... FOR UPDATE 或者 SELECT ... LOCK IN SHARE MODE 语句来加锁,从而避免并发事务之间的写入冲突。这种方式需要程序员自己进行控制,比较复杂,因此在 MySQL 5.0 中需要更加谨慎地编写程序以避免更新丢失的情况。
MySQL 8.0 如何关闭可重复读隔离级别下的写入冲突检测
在 MySQL 8.0 中,如果要关闭可重复读隔离级别下的写入冲突检测,可以通过设置参数 innodb_autoinc_lock_mode
来实现。该参数用于控制自增长 ID 的锁定方式,可以设置为如下两种值之一:
0
:表示关闭写入冲突检测,即不进行行级锁定,会出现更新丢失的情况。1
:表示开启写入冲突检测,使用行级锁定来避免并发事务之间的写入冲突。要关闭可重复读隔离级别下的写入冲突检测,可以使用如下命令:
SET GLOBAL innodb_autoinc_lock_mode=0;
也可以在 MySQL 的配置文件 my.cnf
或者 my.ini
中添加以下参数:
[mysqld]
innodb_autoinc_lock_mode=0
需要注意的是,关闭写入冲突检测会导致并发事务之间的写入冲突,并且可能导致数据的不一致性。因此,在实际应用中,需要根据具体情况谨慎地选择是否关闭写入冲突检测。
ERROR 1238 (HY000): Variable 'innodb_autoinc_lock_mode' is a read only variable
如果在 MySQL 8.0 中执行 SET GLOBAL innodb_autoinc_lock_mode=0;
出现 ERROR 1238 (HY000): Variable 'innodb_autoinc_lock_mode' is a read only variable
的错误,可能是因为 MySQL 8.0 中 innodb_autoinc_lock_mode
这个参数已经被标记为只读变量,不能通过 SET
命令来修改。
如果要关闭可重复读隔离级别下的写入冲突检测,可以通过修改 MySQL 的配置文件 my.cnf
或者 my.ini
来实现。在 my.cnf
或者 my.ini
中添加以下参数:
[mysqld]
innodb_autoinc_lock_mode=0
然后重启 MySQL 服务,这样就可以关闭可重复读隔离级别下的写入冲突检测了。需要注意的是,关闭写入冲突检测会导致并发事务之间的写入冲突,并且可能导致数据的不一致性。因此,在实际应用中,需要根据具体情况谨慎地选择是否关闭写入冲突检测。
可以仅在一个事务中关闭吗
在 MySQL 8.0 中,不支持在一个事务中临时关闭可重复读隔离级别下的写入冲突检测。如果要关闭可重复读隔离级别下的写入冲突检测,只能通过修改 MySQL 的全局参数 innodb_autoinc_lock_mode
来实现,这样会影响到整个 MySQL 实例中的所有事务。
如果需要在某个特定的事务中禁用行级锁定机制,可以通过更改事务隔离级别来实现。可以将事务隔离级别设置为读已提交(Read Committed),这样事务就不会使用可重复读隔离级别下的行级锁定机制了。可以通过以下命令将事务隔离级别设置为读已提交:
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
需要注意的是,将事务隔离级别设置为读已提交会影响到事务的并发性能,可能会导致更多的锁争用和死锁问题。因此,在实际应用中,需要根据具体情况进行权衡和选择。
my.ini在哪
An error occurred with your deployment
EDGE_FUNCTION_INVOCATION_TIMEOUT