MySQL并发开启事务与隔离级别相关

发布时间 2023-08-09 13:48:17作者: 江湖乄夜雨

? 环境MySQL8.0

MySQL: 8.0

Golang: go 1.18

? 相关知识点储备

❗️数据库事务与MySQL事务总结

彻底搞懂 MySQL 事务的隔离级别

一文搞懂InnoDB MVCC机制

? MySQL5.7查询与修改数据库的隔离级别

MySQL查看和修改事务隔离级别

-- 查看隔离级别
show variables like '%tx_isolation%';
select @@tx_isolation;

-- 查看 global/session 级别的隔离级别
SELECT @@global.tx_isolation; -- 默认的是 REPEATABLE-READ
SELECT @@session.tx_isolation;

-- 修改 global/session 级别的隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;


-- 还可以使用 set tx_isolation 命令直接修改当前 session 的事务隔离级别
set tx_isolation='READ-COMMITTED';

? MySQL8.0查询与设置事务的隔离级别

❗️MySQL8.0 查询与设置事务隔离级别

MySQL8.0 已删除原来的 tx_isolation ,改用 transaction_isolation

transaction_isolation was added in MySQL 5.7.20 as an alias for tx_isolation, 
which is now deprecated and is removed in MySQL 8.0. 
Applications should be adjusted to use transaction_isolation in preference to tx_isolation. 

查询默认事务隔离级别

# 1 查询 global与session范围的 隔离级别
SELECT @@global.transaction_isolation AS 'Global Isolation Level';
SELECT @@session.transaction_isolation AS 'Session Isolation Level';

# 2
show variables like 'transaction_isolation';
# 3
select @@transaction_isolation;
# 4
SELECT @@GLOBAL.transaction_isolation, @@GLOBAL.transaction_read_only;

检查会话中的事务隔离级别

SELECT @@SESSION.transaction_isolation, @@SESSION.transaction_read_only;

? MySQL8.0设置事务隔离级别语法

✅ 方式1:通过set命令

SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL level;

-- 其中level有4种值:
level: {
     REPEATABLE READ
   | READ COMMITTED
   | READ UNCOMMITTED
   | SERIALIZABLE
}


-- 全局级别的
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;


-- session会话级别的
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;


-- 无关键词的
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;


关键词:GLOBAL
SET GLOBAL TRANSACTION ISOLATION LEVEL level;
-- 只对执行完该语句之后产生的会话起作用
-- 当前已经存在的会话无效
关键词:SESSION
SET SESSION TRANSACTION ISOLATION LEVEL level;
-- 对当前会话的所有后续的事务有效
-- 该语句可以在已经开启的事务中间执行,但不会影响当前正在执行的事务
-- 如果在事务之间执行,则对后续的事务有效。
无关键词
SET TRANSACTION ISOLATION LEVEL level;
-- 对当前会话中下一个即将开启的事务有效
-- 下一个事务执行完后,后续事务将恢复到之前的隔离级别
-- 该语句不能在已经开启的事务中间执行,会报错的

✅ 方式2:通过服务启动项命令

可以修改启动参数transaction-isolation的值

比方说我们在启动服务器时指定了--transaction-isolation=READ UNCOMMITTED,那么事务的默认隔离级别就从原来的REPEATABLE READ变成了READ UNCOMMITTED。

✅ 在项目中演示并发事务与隔离级别设置的关系(没演示出来)

1.REPEATABLE-READ的情况

没报错~

2.READ-COMMITTED的情况

没报错~

?❗️ Chat-GPT: 并发事务出现invalid connection可能原因

使用gorm操作MySQL,我开启了并发事务 然后报错了: invalid connection,请问可能是什么原因呢❓

报错信息 "invalid connection" 可能是由于以下几个原因引起的:

  1. 连接池设置不当:并发事务可能导致连接池资源不足。如果连接池的最大连接数设置较小,并发事务请求超过了该限制,就会导致连接不足,进而出现 "invalid connection" 错误。可以考虑增大连接池的最大连接数来解决这个问题。

  2. 连接过期:如果连接在长时间没有使用后被数据库服务器关闭,而在并发事务时尝试重新使用已失效的连接,就会报 "invalid connection" 错误。这通常是由于数据库服务器的超时设置导致的。可以尝试减少连接空闲时间或者调整数据库服务器的超时设置。

  3. 并发冲突:可能存在并发事务之间的冲突,例如在同一个连接上同时执行了两个事务并试图修改相同的数据。这可能导致其中一个事务失败并报错 "invalid connection"。在使用并发事务时,应该确保事务之间的操作是合理的,避免并发冲突。

  4. 事务处理不当:在使用 GORM 进行并发事务时,可能由于代码逻辑错误或异常情况导致事务没有正确地提交或回滚,从而导致连接状态不一致,进而报错 "invalid connection"。应该仔细检查代码中的事务处理逻辑,确保每个事务都正确地提交或回滚。

解决该问题的方法:

  • 确保连接池设置合理,并且最大连接数足够满足并发事务的需求。
  • 检查数据库服务器的连接超时设置,确保连接不会因长时间空闲而被关闭。
  • 确保并发事务之间没有冲突,并且合理处理事务的提交和回滚逻辑。
  • 在出现 "invalid connection" 错误时,可以尝试重新连接数据库,并进行适当的错误处理和重试机制。

如果以上方法都无法解决问题,建议查看具体的错误日志和调试信息,以便更准确地定位和解决问题。

? Chat-GPT: MySQL并发开启事务 什么情况下会报错

In MySQL, concurrent transactions can encounter errors in various scenarios due to the way transactions and isolation levels work. Here are some common situations when concurrent transactions might result in errors:

  1. Deadlocks: A deadlock occurs when two or more transactions are waiting for each other to release locks on resources. If this wait becomes indefinite, MySQL will automatically detect the deadlock and terminate one of the transactions with a deadlock error. The error message typically indicates which transaction was chosen as the deadlock victim.
  2. Lock Timeout: If a transaction tries to acquire a lock on a resource that is already locked by another transaction, it may have to wait for the lock to be released. If the wait time exceeds the lock timeout limit, MySQL will throw a lock timeout error, indicating that the transaction was unable to acquire the required lock.
  3. Serialization Failures: In some cases, when two or more transactions try to modify the same data concurrently, the database system may not be able to serialize their operations properly. This can lead to a serialization failure, and MySQL will throw a serialization failure error, indicating that the transactions cannot be executed in the desired order.
  4. Explicit Lock Conflicts: If a transaction explicitly requests a lock that conflicts with the lock held by another transaction, MySQL will report a lock conflict error. For example, if one transaction acquires an exclusive lock on a row, another transaction trying to acquire an exclusive lock on the same row will result in a lock conflict error.
  5. Lost Updates: When multiple transactions concurrently modify the same data without proper synchronization, some updates may be lost, leading to data inconsistency. While this may not cause an immediate error, it can lead to unexpected and incorrect results.

To handle these situations, it's important to implement proper error handling and transaction retry mechanisms in your application code. Additionally, it's crucial to design your database schema and queries efficiently to minimize the likelihood of encountering such errors. Properly managing transactions, using the right isolation level, and ensuring that transactions are as short-lived as possible can also help mitigate these issues.

? Chat-GPT: 并发事务出现的“幻读”问题

在MySQL中,并发开启事务通常不会有问题,因为MySQL具有良好的事务管理机制和隔离级别控制,可以处理多个并发事务的同时执行。然而,当事务隔离级别设置不当或者应用程序对事务处理不当时,可能会导致并发事务产生问题。

一个例子是著名的"幻读"问题,它是在REPEATABLE READ隔离级别下可能发生的一种情况。在这个隔离级别下,一个事务在执行期间可以看到其它事务插入的新行,但是不会看到已删除的行。然而,它仍然会看到已经存在的行。这可能导致在事务执行过程中,有些行似乎“突然出现了”,或者“突然消失了”,就好像出现了幻觉一样,因此称为"幻读"。

下面是一个简单的例子,展示了在REPEATABLE READ隔离级别下可能发生幻读的情况:

假设有一张表"products"包含两行数据:

id product_name quantity
1 Laptop 10
2 Smartphone 15

现在,假设有两个并发的事务:

事务1执行以下操作:

START TRANSACTION;
UPDATE products SET quantity = 20 WHERE id = 1;

事务2执行以下操作:

START TRANSACTION;
INSERT INTO products (id, product_name, quantity) VALUES (3, 'Tablet', 25);

在REPEATABLE READ隔离级别下,事务1开始执行后,事务2插入了一行新数据(id=3),但是事务1并不会看到这个新数据,因为事务1的快照是在它开始执行时创建的。所以,在事务1中执行查询SELECT * FROM products;时,只会看到id为1和2的两行数据。

然而,一旦事务1提交了,事务2再执行查询SELECT * FROM products;时,就会看到id为1、2和3的三行数据。这就是一个幻读的例子,因为在事务2的执行过程中,有一个新的行似乎“突然出现了”。

幻读问题通常可以通过升级到SERIALIZABLE隔离级别来解决,这将强制MySQL在处理并发事务时对数据进行更严格的锁定,避免了幻读问题。不过需要注意的是,升级到SERIALIZABLE隔离级别可能会导致性能下降,因为它会引入更多的锁竞争。在实际应用中,需要根据具体情况进行权衡。