以下两条事务发生更新丢失的情况:BEGIN; SELECT count FROM test; UPDATE test SET count=1 WHERE count=0; COMMIT;

2023-04-18by@3275447638-bcVhS&@yijiayi01.Model: gpt-3.5
3275447638-bcVhS

以下两条事务发生更新丢失的情况:BEGIN;
SELECT count FROM test;
UPDATE test SET count=1 WHERE count=0;
COMMIT;

Avatar
Avatar
  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语句并将count的值更新为1并提交事务。这时候,第二个事务覆盖了第一个事务的更新,导致第一个事务的更新丢失。

  2. 当两个事务同时开始时,第一个事务(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并提交事务。这时候,第二个事务覆盖了第一个事务的更新,导致第一个事务的更新丢失。

3275447638-bcVhS

以下两条事务发生更新丢失的情况: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;

Avatar
Avatar

当两个事务同时开始时,第一个事务(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并提交事务。这时候,第二个事务覆盖了第一个事务的更新,导致第一个事务的更新丢失。

3275447638-bcVhS

但在msql 8.0上的执行结果为1,为什么

Avatar
Avatar

MySQL 8.0 引入了可重复读隔离级别下的写入冲突检测,可以防止更新丢失的情况,从而避免了并发事务之间的写入冲突。在可重复读隔离级别下,当一个事务执行 UPDATE 或者 DELETE 语句的时候,MySQL 会对数据行加锁,其他事务不能对这个数据行进行写入,直到这个事务提交或者回滚。因此,当两个事务同时执行 UPDATE 语句时,后执行的事务会因为加锁失败而被阻塞,直到前一个事务提交或者回滚后才能继续执行更新操作。

在你的情况下,第一个事务执行 UPDATE 语句并提交后,第二个事务执行 UPDATE 语句时会因为行锁而被阻塞,直到第一个事务提交后才能继续执行。因此,第二个事务实际上没有修改任何数据,因此查询的结果仍然为1。

3275447638-bcVhS

mysql5.0下也有此机制吗

Avatar
Avatar

在 MySQL 5.0 中,也有锁机制和事务隔离级别的概念,但是 MySQL 5.0 默认的隔离级别是可重复读,而不是读已提交。因此,在 MySQL 5.0 中,如果两个事务同时执行 UPDATE 语句,就可能发生更新丢失的情况。在这种情况下,后执行的事务会覆盖先执行的事务的更新结果。

不过,MySQL 5.0 也提供了行级锁机制,可以通过显式地使用 SELECT ... FOR UPDATE 或者 SELECT ... LOCK IN SHARE MODE 语句来加锁,从而避免并发事务之间的写入冲突。这种方式需要程序员自己进行控制,比较复杂,因此在 MySQL 5.0 中需要更加谨慎地编写程序以避免更新丢失的情况。

3275447638-bcVhS

MySQL 8.0 如何关闭可重复读隔离级别下的写入冲突检测

Avatar
Avatar

在 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

需要注意的是,关闭写入冲突检测会导致并发事务之间的写入冲突,并且可能导致数据的不一致性。因此,在实际应用中,需要根据具体情况谨慎地选择是否关闭写入冲突检测。

3275447638-bcVhS

ERROR 1238 (HY000): Variable 'innodb_autoinc_lock_mode' is a read only variable

Avatar
Avatar

如果在 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 服务,这样就可以关闭可重复读隔离级别下的写入冲突检测了。需要注意的是,关闭写入冲突检测会导致并发事务之间的写入冲突,并且可能导致数据的不一致性。因此,在实际应用中,需要根据具体情况谨慎地选择是否关闭写入冲突检测。

3275447638-bcVhS

可以仅在一个事务中关闭吗

Avatar
Avatar

在 MySQL 8.0 中,不支持在一个事务中临时关闭可重复读隔离级别下的写入冲突检测。如果要关闭可重复读隔离级别下的写入冲突检测,只能通过修改 MySQL 的全局参数 innodb_autoinc_lock_mode 来实现,这样会影响到整个 MySQL 实例中的所有事务。

如果需要在某个特定的事务中禁用行级锁定机制,可以通过更改事务隔离级别来实现。可以将事务隔离级别设置为读已提交(Read Committed),这样事务就不会使用可重复读隔离级别下的行级锁定机制了。可以通过以下命令将事务隔离级别设置为读已提交:

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

需要注意的是,将事务隔离级别设置为读已提交会影响到事务的并发性能,可能会导致更多的锁争用和死锁问题。因此,在实际应用中,需要根据具体情况进行权衡和选择。

3275447638-bcVhS

my.ini在哪

Avatar
Avatar

An error occurred with your deployment

EDGE_FUNCTION_INVOCATION_TIMEOUT