事务介绍
1. 事务是数据库系统区别其他一切文件系统的重要特征。文件系统不能保证修改两个文件保存内容一致。
2. 事务是由一组具有原子性的sql语句或者是一个独立的工作单元。可以是一个sql,或者有多个增删改查组成的sql语句集合。
3. 事务是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。通常一个事务对应一个完整的业务(例如银行账户转账业务,该业务就是一个最小的工作单元)
一个完整的业务需要批量的DML(insert、update、delete)语句共同联合完成
Mysql事务的特性四个特性(ACID)
1. 原子性(Atomicity,或称不可分割性):事务中所有的操作,要么都执行成功,要么其中有一条失败就全部都不执行
2. 一致性(Consistency)
3. 隔离性(Isolation)
4. 持久性(Durability)
在 MySQL 中,事务支持是在引擎层实现的。
并不是所有引擎都支持事务,如 MyISAM 就不支持,InnoDB 就支持;
事务并发的问题
1. 脏读(Dirty Reads):一个事务正在对一条记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致状态。这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”数据,并据此做进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象地叫做"脏读"。
2. 不可重复读(Non-Repeatable Reads):一个事务读取某些数据,在它结束读取之前,另一个事务可能完成了对数据行的更改。当第一个事务试图再次执行同一个查询,服务器就会返回不同的结果。
3. 幻读(Phantom Reads):一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。
事务隔离级别
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read-uncommitted) | 是 | 是 | 是 |
不可重复读(read-committed) | 否 | 是 | 是 |
可重复读(repeatable-read) | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
事务的操作和状态
1. 开启事务:Start Transaction。
2. 提交事务:Commit Transaction。
3. 回滚事务:Rollback Transaction。
4. 事务结束:End Transaction。
TCL语句
1. commit: 提交事务。
2. rollback:回滚事务。
在MySQL中默认事务是自动提交的,也就是说只要执行一条DML语句就开启了事物,并且提交了事务。
未提交事务
长期未提交事务,指开启事务后,长时间未向MySQL发出SQL执行请求或事务处理(COMMIT/ROLLBACK)请求,在系统表`information_schema`.`INNODB_TRX` 中状态为RUNNING,而在`information_schema`.`PROCESSLIST`中状态为SlEEP。
导致事务长期未提交的因素很多,常见的有:
1、事务过程中执行其他非数据库操作,导致事务长期未被处理。
2、事务处理异常或实现逻辑有误,导致事务未被正常处理。
3、网段异常导致应用端请求未被正常发送给数据库,数据库等待应用后续操作。
4、应用服务器性能问题(如CPU爆满),导致应用无法及时切换到该进程进行处理。
与事务相关的两个日志文件
1. 重做日志(redo log):确保事务的持久性。防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo log进行重做,从而达到事务的持久性这一特性。
2. 回滚日志(undo log):保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),即非锁定读。
redo log/undo log和二进制日志的区别
- 二进制日志是在Mysql服务层,不管是什么存储引擎,对数据库进行了修改都会产生二进制日志。而redo log/undo log是innodb层产生的,只记录该存储引擎中表的修改。并且二进制日志先于redo log/undo log被记录。
- 二进制日志记录操作的方法是逻辑性的语句。即便它是基于行格式的记录方式,其本质也还是逻辑的SQL设置,如该行记录的每列的值是多少。而redo log是在物理格式上的日志,它记录的是数据库中每个页的修改。
- 二进制日志只在每次事务提交的时候一次性写入缓存中的日志"文件"(对于非事务表的操作,则是每次执行语句成功后就直接写入)。而redo log在数据准备修改前写入缓存中的redo log中,然后才对缓存中的数据执行修改操作;而且保证在发出事务提交指令时,先向缓存中的redo log/undo log写入日志,写入完成后才执行提交动作。
Innodb如何解决幻读
MySQL 5.5 版本以后,information_schema(ski:mə) 库中新增了三个关于锁的表,亦即 innodb_trx
、innodb_locks
和 innodb_lock_waits
。其中 innodb_trx
表记录当前运行的所有事务,innodb_locks
表记录当前出现的锁,innodb_lock_waits
表记录锁等待的对应关系。
下面对 innodb_trx
表的每个字段进行解释:
trx_id:事务ID。
trx_state:事务状态,有以下几种状态:RUNNING、LOCK WAIT、ROLLING BACK 和 COMMITTING。
trx_started:事务开始时间。
trx_requested_lock_id:事务当前正在等待锁的标识,可以和 INNODB_LOCKS 表 JOIN 以得到更多详细信息。
trx_wait_started:事务开始等待的时间。
trx_weight:事务的权重。
trx_mysql_thread_id:事务线程 ID,可以和 PROCESSLIST 表 JOIN。
trx_query:事务正在执行的 SQL 语句。
trx_operation_state:事务当前操作状态。
trx_tables_in_use:当前事务执行的 SQL 中使用的表的个数。
trx_tables_locked:当前执行 SQL 的行锁数量。
trx_lock_structs:事务保留的锁数量。
trx_lock_memory_bytes:事务锁住的内存大小,单位为 BYTES。
trx_rows_locked:事务锁住的记录数。包含标记为 DELETED,并且已经保存到磁盘但对事务不可见的行。
trx_rows_modified:事务更改的行数。
trx_concurrency_tickets:事务并发票数。
trx_isolation_level:当前事务的隔离级别。
trx_unique_checks:是否打开唯一性检查的标识。
trx_foreign_key_checks:是否打开外键检查的标识。
trx_last_foreign_key_error:最后一次的外键错误信息。
trx_adaptive_hash_latched:自适应散列索引是否被当前事务锁住的标识。
trx_adaptive_hash_timeout:是否立刻放弃为自适应散列索引搜索 LATCH 的标识。