事务相关

事务

事务(Transaction)是一组SQL组成的执行单元(unit),是数据库并发控制和恢复回滚的基本单位

一个事务可能包含多个SQL,要么都失败,要么都成功

事务具备4个基本属性:

Atomic,同一个事务里,要么都提交,要么都回滚

Consistency,即在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏

Isolation,并发事务间的数据是彼此隔离的

Durability,事务提交后,所有结果务必被持久化

支持事务的引擎:InnoDB、TokuDB、MyRocks

不支持事务的引擎:MyISAM、MEMORY/HEAP

mysql> show enginesG

显示开始事务 

START TRANSACTION

    [READ WRITE]  默认

    [WITH CONSISTENT SNAPSHOT]

    [READ ONLY]

BEGIN/BEGIN WORK

开启/关闭自动提交

set autocommit | @@autocommit = 0 | 1

提交事务

显示提交

COMMIT

隐式提交

BEGIN/BEGIN WORK

START TRANSACTION

SET AUTOCOMMIT = 1

其他非事务语句(DDL/DCL)

回滚事务

显式回滚

ROLLBACK

隐式回滚

连接断开,mysql > exit;

超时断开,mysql > timeout; 锁等待超时

被kill,mysql > kill x;

异常宕机

autocommit = 0 必要吗

好处:

    多语句提交时,不会每个SQL单独提交,提高事务提交效率

麻烦:

    有个事务忘记提交,锁一直未释放

    另一个事务长期锁等待,严重影响tps

Python中的autocommit

import MySQLdb
from time import sleep
conn = MySQLdb.connect(host='1.2.3.4',port=3306,user='app')
conn.autocommit = True
cur = conn.cursor()
cur.execute("show global status")
while 1:
    sleep(1)

是Python方法,而不是数据库的

cur.execute("set autocommit=1") 才是数据库的

事务隔离级别

如果没有事务控制的话,那么并发读写数据库会有什么隐患

脏读:

事务T1修改了一行数据,事务T2在事务T1提交之前读到了该行数据

不可重复读:

同样的条件,读取过的数据,再次读取出来发现值不一样了,更改数据(修改或删除)

幻读:

同样的条件,第1次和第2次读取出来的记录数不一样,新增数据

丢失更新:

第一类丢失更新,即回滚导致的另一个事务的更新丢失

第二类丢失更新,即事务A覆盖事务B已经提交的数据

Read Uncommitted (读未提交) 隔离级别最低

允许脏读,允许事务查看其他事务所进行的未提交的更改

Read Committed (读已提交)

允许幻读,不可重复读,允许事务查看其他事务所进行的已提交的更改

Repeatable Read (可重复读)

消除了脏读,不可重复读,幻读,保证事务一致性

确保每个事务的读取结果总是一样,默认隔离级别

Serializable (串行) 隔离级别最高

串行化读,每次读都需要获得表级共享锁,读写间相互都会阻塞

隔离级别和可能发现的现象总结如下:

my.cnf配置

[mysqld]分段中,加入一行

transaction-isolation = "READ-COMMITTED" #默认值是REPEATABLE-READ

在线(全局)修改

set [global] transaction isolation level read committed;

查看当前隔离级别

select @@global.transaction_isolation,@@session.transaction_isolation;

https://blog.csdn.net/qq_37771475/article/details/86493631 很详细

InnoDB读

快照读,snapshot read

    基于read view读可见版本,不加锁

    start transaction with consistent read + select

    普通select

    由基于某个时间点的一组InnoDB内部(活跃)事务构建而成的列表

当前读,current read

    读(已提交的)最新版本,并加锁

    select ... for update/lock in share mode

    DML

InnoDB只读事务

5.6开始支持

5.7进一步优化,不记录redo log

5.7起,非显示声明的事务,默认都是以只读模式启动,事务过程中有数据被修改时,才自动变更为读写模式

显式声明的只读事务时innodb_trx.trx_is_read_only = 1

mysql> start transaction read only; 

mysql> select * from t1;

InnoDB是如何解决幻读的

RR级别下解决了幻读问题

引入gap lock,把2条记录中间的gap锁住,避免其他事务写入

存在幻读的条件:

    <= RC级别

    innodb_locks_unsafe_for_binlog = 1

8.0版本innodb_lock_unsafe_for_binlog没有这个参数

InnoDB semi-consistent read

semi-consistent read是read committed与consistent read的结合 

一个update语句,如果读到一行已经加锁的记录,此时InnoDB返回记录最近提交的版本,由MySQL上层判断此版本是否满足update的where条件。若满足,则MySQL会重新发起一次读操作,此时会读取行的最新版本(并加锁)

semi-consistent read发生的条件:

    <= read committed隔离级别

    innodb_locks_unsafe_for_binlog = 1 时

    update请求(不含insert、delete)

原文地址:https://www.cnblogs.com/allenhu320/p/11365064.html