开云体育官方网站 事务破损级别

在mysql中,如若有深广用户同期拜谒修改并吞条数据,将会产生数据一致性的问题,本文来沟通mysql是如何处理这个问题的。
场景预设CREATE DATABASE IF NOT EXISTS `isolation_lab`;
USE `isolation_lab`;
--
DROP TABLE IF EXISTS `account`; CREATE TABLE `account` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(50) NOT NULL, `balance` DECIMAL(10,2) NOT NULL DEFAULT 0.00, `version` INT DEFAULT 0 ) ENGINE=InnoDB;
--
INSERT INTO `account` (`name`, `balance`) VALUES ('张三', 1000.00), ('李四', 500.00), ('王五', 2000.00);
-- #MySQL #SQL #每天一个常识点
DROP TABLE IF EXISTS `transaction_log`; CREATE TABLE `transaction_log` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `from_account` VARCHAR(50), `to_account` VARCHAR(50), `amount` DECIMAL(10,2), `create_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB;
并发事务的三大问题脏读脏读 等于读取到了其他事务尚未提交的数据,底下来创建一个脏读的情况 脏数据 是指 未提交的、不踏实的临时数据 。
--
-- 需要两个寂静的 MySQL 客户端会话(会话 A 会通话 B)
--
--
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; START TRANSACTION;
--
UPDATE account SET balance = balance - 200 WHERE name = '张三';
--
--
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; START TRANSACTION;
--
SELECT balance FROM account WHERE name = '张三'; -- 效果:800.00(但会话 A 可能随时回滚!)
--
--
ROLLBACK;
--
--
SELECT balance FROM account WHERE name = '张三'; -- 效果:1000.00(刚才读到的800是"脏数据")
这种情况会导致会话 B 很可能凭证读取到的800来作念出一些有贪图,然而会话 A 又回滚数据了,导致会话 B 的后续有贪图(针对800)是关于实践的1000这个数据作念的。
或者会话 A 插入一条新的数据,但未提交,会话 B 凭证这条新数据作念了操作,会话 A 回滚,导致业务逻辑十足乖张。
不能重读不能重读 等于并吞事务中屡次读取并吞数据,效果 不一致 --
UPDATE account SET balance = 1000.00 WHERE name = '张三';
--
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; START TRANSACTION;
--
SELECT balance FROM account WHERE name = '张三'; -- 效果:1000.00
--
--
START TRANSACTION; UPDATE account SET balance = 800.00 WHERE name = '张三'; COMMIT;
--
--
SELECT balance FROM account WHERE name = '张三'; -- 效果:800.00(与第一次读取不一致!)
--
--
COMMIT;
有东谈主可能会很猜忌,并吞事务中屡次读取并吞数据,效果不一致 ,是不能重读,那 脏读 不相通是在一个事务中可能读到不同的数据吗?
其实质分手是: 脏读 是读取了 事务未提交 的数据, 不能重读 是读取了 其他事务还是提交的数据 2. 脏读 的数据是临时的,可能被回滚,从未的确见效, 不能重读 的数据是真实的幻读幻读 是并吞事务中屡次查询,复返的 行数 不一致
--
--
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; --
START TRANSACTION;
--
SELECT COUNT(*) FROM account WHERE balance > 600; -- 效果:2(张三1000,王五2000)
--
--
START TRANSACTION; INSERT INTO account (name, balance) VALUES ('赵六', 700.00); COMMIT;
--
--
SELECT COUNT(*) FROM account WHERE balance > 600; -- 效果:2(在 REPEATABLE READ 下看不到新插入的赵六)
--
UPDATE account SET version = version +
SELECT ROW_COUNT; -- 影响了3行!包括赵六!
--
SELECT COUNT(*) FROM account WHERE balance > 600; --
COMMIT;
这个效果相配的神奇,kaiyun sports那么到底发生了什么,会产生这种情况?
因为在 可重叠读 这个事务破损级别中,具有 快照读 和 现时读 两种机制:
第一次使用 select 进行查询时,使用的是 快照读 ,它读取的是事务运转的技能 数据的快照 ,因此看不见之前由其他事务提交的新增事务。在使用 update 语句进行更新时,因为要确保更新的数据是基于最新的、还是提交的情状,因此数据库必须进行 现时读 ,因此 update 语句不祥感知到其他事务新提交的那札纪录。何况,当数据库发现新纪录是恰当 update 中的 where 语句,就会对其也进行更新,还会将这札纪录 创建版块 的 trx_id (事务ID)成立为现时更新事务的ID。第二次使用 select 进行查询时,依旧使用的是 快照读 ,快照读的规章是: 只读取在事务运转时就还是提交的数据版块,或者由才智务自己创建的数据版块 ,因此当今不错读取到新纪录。四种破损级别读未提交(READ UNCOMMITTED) - 性能最佳,一致性最差--
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
--
--
--
-- 使用场景:对数据一致性条目极低,照及时性条目极高的监控系统
{jz:field.toptypename/}读已提交(READ COMMITTED) - Oracle/PostgreSQL默许SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
--
--
--
--
-- 使用场景:大多数 OLTP 系统
可重叠读(REPEATABLE READ) - MySQL默许SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
--
--
--
--
-- 使用场景:需要事务内数据一致性的场景
串行化(SERIALIZABLE) - 一致性最佳,性能最差SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
--
--
--
--
-- 用场景:对一致性条目极高,如金融中枢系统
破损级别实践影响C READ UNCOMMITTED--
UPDATE account SET balance = 1000.00 WHERE name = '张三'; UPDATE account SET balance = 500.00 WHERE name = '李四'; UPDATE account SET balance = 2000.00 WHERE name = '王五'; DELETE FROM account WHERE name = '赵六';
--
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; START TRANSACTION; --
SELECT SUM(balance) AS total_before FROM account; -- 假定看到3500
--
START TRANSACTION; UPDATE account SET balance = balance -
-- 还没提交!
-
UPDATE account SET balance = balance *
--
COMMIT;
--
ROLLBACK; -- 转账失败,但利息已乖张计较!
REPEATABLE READ--
UPDATE account SET balance = 1000.00 WHERE name = '张三'; UPDATE account SET balance = 500.00 WHERE name = '李四'; UPDATE account SET balance = 2000.00 WHERE name = '王五';
--
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; START TRANSACTION; SELECT SUM(balance) AS total_before FROM account; -- 看到3500
--
START TRANSACTION; UPDATE account SET balance = balance -
COMMIT; -- 提交到手
--
SELECT SUM(balance) AS total_now FROM account; --
UPDATE account SET balance = balance *
COMMIT; -- 提交后,其他事务看到更新

备案号: