「这是我参与11月更文挑战的第21天,活动详情查看:2021最后一次更文挑战」
问题:mysql执行update语句时,如果不是主键where语句会报错
原因:MySql运行在safe-updates模式下,该模式会导致非主键条件下无法执行update或者delete命令
解决:
查看状态
1 | sql复制代码SHOW VARIABLES LIKE 'SQL_SAFE_UPDATES'; |
开启
1 | ini复制代码SET SQL_SAFE_UPDATES = 0; |
安装binlog记录日志
安装binlog2sql
1 | bash复制代码git clone https://github.com/danfengcao/binlog2sql.git |
修改mysql的配置文件my.cnf
不知道my.cnf所在路径 可以用以下命令查询
1 | bash复制代码sudo find / -name my.cnf |
添加如下配置
1 | bash复制代码[mysqld] |
数据库事务
事务的特性 ACID
Atomacity 原子性
Consistency 一致性
Isolation 隔离性
Durability 持久性
事务的隔离级别
- 脏读(Dirty Read)
当一个事务读取另一个事务尚未提交的修改时,产生脏读。
一个事务开始读取了某行数据,但是另外一个事务已经更新了此数据但没有能够及时提交。
- 非重复度(Nonrepeatable Read)
一个事务对同一行数据重复读取两次,但是却得到了不同的结果。同一查询在同一事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时发生非重复读。
- 幻想读(Phantom Reads)
事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据(这里并不要求两次查询的SQL语句相同)。这是因为在两次查询过程中有另外一个事务插入数据造成的。
Isolation Level | 脏读(Dirty Read) | 不可重复读(Non Repeatable Read) | 幻读(Phantom Read)Read |
---|---|---|---|
Read Uncommitted | Yes | Yes | Yes |
Read Committed | - | Yes | Yes |
Repeatable Read | - | - | Yes |
Serializable | - | - | - |
Read Uncommitted
Read Uncommitted是隔离级别最低的一种事务级别。在这种隔离级别下,一个事务会读到另一个事务更新后但未提交的数据,如果另一个事务回滚,那么当前事务读到的数据就是脏数据,这就是脏读(Dirty Read)。
时刻 | 事务A | 事务B |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
2 | BEGIN; | BEGIN; |
3 | UPDATE students SET name = ‘Bob’ WHERE id = 1; | |
4 | SELECT * FROM students WHERE id = 1; | |
5 | ROLLBACK; | |
6 | SELECT * FROM students WHERE id = 1; | |
7 | COMMIT; |
当事务A执行完第3步时,它更新了id=1
的记录,但并未提交,而事务B在第4步读取到的数据就是未提交的数据。
随后,事务A在第5步进行了回滚,事务B再次读取id=1
的记录,发现和上一次读取到的数据不一致,这就是脏读。
可见,在Read Uncommitted隔离级别下,一个事务可能读取到另一个事务更新但未提交的数据,这个数据有可能是脏数据。
Read Committed
在Read Committed隔离级别下,一个事务可能会遇到不可重复读(Non Repeatable Read)的问题。
不可重复读是指,在一个事务内,多次读同一数据,在这个事务还没有结束时,如果另一个事务恰好修改了这个数据,那么,在第一个事务中,两次读取的数据就可能不一致。
时刻 | 事务A | 事务B |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; |
2 | BEGIN; | BEGIN; |
3 | SELECT * FROM students WHERE id = 1; | |
4 | UPDATE students SET name = ‘Bob’ WHERE id = 1; | |
5 | COMMIT; | |
6 | SELECT * FROM students WHERE id = 1; | |
7 | COMMIT; |
当事务B第一次执行第3步的查询时,得到的结果是Alice
,随后,由于事务A在第4步更新了这条记录并提交,所以,事务B在第6步再次执行同样的查询时,得到的结果就变成了Bob
,因此,在Read Committed隔离级别下,事务不可重复读同一条记录,因为很可能读到的结果不一致。
Repeatable Read
在Repeatable Read隔离级别下,一个事务可能会遇到幻读(Phantom Read)的问题。
幻读是指,在一个事务中,第一次查询某条记录,发现没有,但是,当试图更新这条不存在的记录时,竟然能成功,并且,再次读取同一条记录,它就神奇地出现了。
时刻 | 事务A | 事务B |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; | SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; |
2 | BEGIN; | BEGIN; |
3 | SELECT * FROM students WHERE id = 99; | |
4 | INSERT INTO students (id, name) VALUES (99, ‘Bob’); | |
5 | COMMIT; | |
6 | SELECT * FROM students WHERE id = 99; | |
7 | UPDATE students SET name = ‘Alice’ WHERE id = 99; | |
8 | SELECT * FROM students WHERE id = 99; | |
9 | COMMIT; |
事务B在第3步第一次读取id=99
的记录时,读到的记录为空,说明不存在id=99
的记录。随后,事务A在第4步插入了一条id=99
的记录并提交。事务B在第6步再次读取id=99
的记录时,读到的记录仍然为空,但是,事务B在第7步试图更新这条不存在的记录时,竟然成功了,并且,事务B在第8步再次读取id=99
的记录时,记录出现了。
可见,幻读就是没有读到的记录,以为不存在,但其实是可以更新成功的,并且,更新成功后,再次读取,就出现了。
Serializable
是最严格的隔离级别。在Serializable隔离级别下,所有事务按照次序依次执行,因此,脏读、不可重复读、幻读都不会出现。
虽然Serializable隔离级别下的事务具有最高的安全性,但是,由于事务是串行执行,所以效率会大大下降,应用程序的性能会急剧降低。如果没有特别重要的情景,一般都不会使用Serializable隔离级别。
默认隔离级别
如果没有指定隔离级别,数据库就会使用默认的隔离级别。在MySQL中,如果使用InnoDB,默认的隔离级别是Repeatable Read。
本文转载自: 掘金