MySQL优化-MySQL事务

时间:2020-04-12
本文章向大家介绍MySQL优化-MySQL事务,主要包括MySQL优化-MySQL事务使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
MySQL优化-MySQL事务

事务(transaction)是一组SQL组成的执行单元(unit),是数据库并发控制和恢复回滚的基本单位。
一个事务可能包含多个SQL,要么都失败,要么都成功。
事务具备4个基本属性:ACID
    Atomic,同一个事务里,要么都提交,要么都回滚。
    Consistency,即在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。
    Isolation,并发事务间的数据是彼此隔离的。
    Durability,事务提交后,所有结果务必被持久化。
支持事务的引擎:InnoDB、NDBCluster、TokuDB、RocksDB。
不支持事务的引擎:MyISAM、MEMORY/HEAP。

[dba@localhost:mysql.sock] [(none)]> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine             | Support | Comment                                                        | Transactions | XA   | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| MRG_MYISAM         | YES     | Collection of identical MyISAM tables                          | NO           | NO   | NO         |
| CSV                | YES     | CSV storage engine                                             | NO           | NO   | NO         |
| MyISAM             | YES     | MyISAM storage engine                                          | NO           | NO   | NO         |
| BLACKHOLE          | YES     | /dev/null storage engine (anything you write to it disappears) | NO           | NO   | NO         |
| PERFORMANCE_SCHEMA | YES     | Performance Schema                                             | NO           | NO   | NO         |
| InnoDB             | DEFAULT | Supports transactions, row-level locking, and foreign keys     | YES          | YES  | YES        |
| ARCHIVE            | YES     | Archive storage engine                                         | NO           | NO   | NO         |
| MEMORY             | YES     | Hash based, stored in memory, useful for temporary tables      | NO           | NO   | NO         |
| FEDERATED          | NO      | Federated MySQL storage engine                                 | NULL         | NULL | NULL       |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
9 rows in set (0.00 sec)

显式开始事务
start transaction;
read write
with consistent snapshot
read only -- 默认

begin;/begin work;

关闭自动提交
set autocommit | @@autocommit = 0

提交事物
1.显式提交
    commit;
2.隐式提交
    begin/begin work
    start transaction
    set autocommit = 1
    其他非事务语句DDL/DCL

回滚事务
1.显式回滚
rollback;
2.隐式回滚
连接断开,mysql> exit;
超时断开,mysql> timeout;
被kill,mysql> kill xxx;
异常宕机。


目前还不支持嵌套事务。
DCL、DDL也不支持事务,因此在事务中也不要执行这些。


autocommit = 0 必要吗?
好处:多语句提交时,不会每个SQL单独提交,提高事务提交效率。
麻烦:
    有个事务忘记提交,锁一直未释放。
    另一个事务长期锁等待,严重影响TPS。
尽量不要设置autocommit = 0

Python中的autocommit。
import MySQLdb 或者 import pymysql
from time import sleep
conn = MySQLdb.connect(user='dev',password='123',host='10.0.0.11',port=3306,)
# conn.autocommit = True (这是不对的)
cur.execute("set autocommit=1;") 或者 cur.autocommit(1)
cur = conn.cursor()
cur.execute("show global status;")
while 1:
    sleep(1)


如果没有事务控制的话,那么并发读写数据库会有什么隐患?
脏读:
事务T1修改了一行数据,事务T2在事务T1提交之前读到了该行数据。

不可重复读
事务T1读取了一行数据,事务T2接着修改或者删除了该行数据,当T1再次读取同一行数据的时候,读到的数据是修改之后的或者发现已经被删除了。

幻读:
事务T1读取了满足某条件的一个数据集,事务T2插入了一行或者多行数据满足了T1的选择条件,导致事务T1再次使用同样的选择条件读取的时候,得到了比第一次读取更多的数据集。

事务隔离级别
RU(读未提交)隔离级别最低。
允许脏读,允许事务查看其它事务所进行的未提交的更改。

RC(读已提交)
允许幻读,允许事务查看其它事务所进行的已提交更改。

RR(可重复读)
消除了脏读、不可重复读、幻读、保证事务一致性,确保每个事务的读取结果总是一样,默认隔离级别。

SR(串行)隔离级别最高
串行化读,每次读都需要获得表级共享锁,读写间相互都会阻塞。


my.cnf配置
[mysqld]
transaction-isolation = "READ-COMMITTED"
默认是REPEATABLE-READ,不确定时,就用默认的RR级别。

在线全局修改
set global transaction isolation level read committed;

查看当前隔离级别
[dba@localhost:mysql.sock] [(none)]> select @@global.tx_isolation,@@session.tx_isolation,@@transaction_isolation;
+-----------------------+------------------------+-------------------------+
| @@global.tx_isolation | @@session.tx_isolation | @@transaction_isolation |
+-----------------------+------------------------+-------------------------+
| REPEATABLE-READ       | REPEATABLE-READ        | REPEATABLE-READ         |
+-----------------------+------------------------+-------------------------+
1 row in set, 2 warnings (0.00 sec)


快照读,snapshot read
    基于read view读可见版本,不加锁。
    start transaction with consistent read + select
    普通select
快照,read view
    由基于某个时间点的一组InnoDB内部(活跃)事务构建而成的列表。

当前读,current read
    读(已提交)最新版本,并加锁。
    S锁,select ... share/lock in share mode
    X锁,select ... for update/DML
加 for update 是当前读,排它锁。


大部分情况下,其实选择RC隔离级别就可以,例如常规的游戏、微博、社区、社交等业务场景中。
Oracle和SQL Server默认隔离级别也是RC。
在金融、交易类业务场景中,一方面在业务上要做好数据完整性、一致性判断,在数据库层面,最好也选择RR隔离级别,进一步保障数据可靠性。

InnoDB只读事务
5.6开始支持。
5.7进一步优化,不记录redo log5.7起,非显式声明的事务,默认都是以只读模式启动,事务过程中有数据被修改时,才自动变更为读写模式。
显式声明的只读事务是 innodb_trx.trx_is_read_only = 1


innodb_flush_log_at_trx_commit = 1
sync_binlog = 1
所谓的双1,用于保证数据的持久性。

kill -9 mysqld_pid,如果设置了双1参数是不会出现坏页的。
这种情况下如果出现磁盘坏页,有两种情况:
    1.MySQL的bug。
    2.硬件问题导致。
如果出现坏页,就直接去想把数据尽快恢复出来,不用想其它的了。


InnoDB是如何利用独特的gap lock机制来解决幻读?
RR级别下解决了幻读问题。
引入gap lock,把2条记录中间的gap锁住,避免其他事务写入。
存在幻读的条件。
    <= RC级别。
    innodb_locks_unsafe_for_binlog = 18.0之后废弃该选项)



什么是半一致性读
InnoDB semi-consistent read
semi-consistent read是read committed与consistend read的结合。
update语句如果读到一行已经加锁的记录,此时InnoDB返回该记录(已提交的)最新版本,并再次判断此版本是否满足update的where条件。
若满足(需要更新),则会重新发起一次读操作,此时会读取行的最新版本,并加锁。
semi-consistent read发生的条件。
    <= read committed隔离级别。
    innodb_locks_unsafe_for_binlog = 1 时(8.0之后废弃该选项)
    update请求(不含insert、delete)
本节小结:
    InnoDB特有的半一致性读,是为了提高没索引时的update效率。

原文地址:https://www.cnblogs.com/zhouwanchun/p/12687541.html