说背景 查线上日志有一个报错 "1062: Duplicate entry '54986956' for key 'PRIMARY'",很明显是主键冲突了。
查报错对应的数据表发现,该表的主键是 AUTO_INCREMENT,操作该数据表的语句只有 REPLACE INTO ...,且该语句中不包含主键字段,也就是说主键是 Mysql 引擎层自己维护的
涨知识 REPLACE INTO 是如何执行的?
官方文档:REPLACE works exactly like INSERT, except that if an old row in the table has the same value as a new row for a PRIMARY KEY or a UNIQUE index, the old row is deleted before the new row is inserted.
翻译过来就是:REPLACE 和 INSERT 类似,但是如果表中已经存在与新行相同的 PRIMARY KEY 或 UNIQUE 索引,那么旧行将被删除,然后新行将被插入。
03 | 事务隔离:为什么你改了我还看不见? 07 | 行锁功过:怎么减少行锁对性能的影响? 08 | 事务到底是隔离的还是不隔离的?
一、前置知识 什么是事务?
简单来说,就是保证一组数据库操作要么全部执行成功,要么一个也不执行
事务的ACID A (atomiciy 原子性) 一个事务被视为一个最小的工作单元,该单元内所有的操作要么全部执行要么回滚全部不执行,不可能部分执行;
C (consistency 一致性) 数据必须保证从一种一致性状态转换为另一种一致性状态; eg:A 转账给 B 100元,那么转账操作前是一种一致性状态,转账成功后 A 少了100元,B 多了100元,这是另一种一致性状态;
I (isolation 隔离性) 并发执行的多个事务之间互不干扰;
D (durability 持久性) 一旦事务提交,该事务所做的更改会被永久保存在数据库中;
tip: 一致性是最基本的属性,其它三个属性可以说都是为了保证数据的一致性; A 通过 undo log 实现;D 通过 redo log 实现;I 通过锁实现;
多个事务并发可能会产生的问题 脏读 事务一在执行过程中修改了记录a,且事务一未完成处于不一致状态时,事务二读取了记录a,并据此做进一步处理,不巧的是事务一执行了回滚操作,这个时候我们认为事务二读取了脏数据,称之为脏读;
不可重复读 在同一个事务内,两个相同的查询返回了不同的结果;
幻读 在同一个事务内,两个相同读查询返回读结果集数量不一致;
不可重复读与幻读读区别
不可重复读的重点在于 update & delete,强调的是同一个查询返回的内容不同;在可重复读隔离级别中,当事务第一次读取了一部分数据后就会对这部分数据加锁,其它事务无法操作这部分数据,这就实现了可重复读,但是这种锁无法避免其它事务的insert操作,这就会导致另一个问题:幻读; 幻读的重点在于insert,强调的是同一个查询返回的结果集数量不一致; 为了解决事务的并发问题:事务隔离 读未提交 一个事务还没提交时,它做的变更就能被别的事务看到。
读提交 一个事务提交之后,它做的变更才会被其他事务看到。
可重复读 一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
串行化 对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。