目录
一、数据库事务概括
1、基本概括:
事务是数据库区别于文件系统的量要特性之一,当我们有了事务就会让数据库始终保持 一致性,同时我们还能通过亭务的机制恢复到某个时间点,这样可以保证已提交到数据库的修改不会因为系统崩溃而丢失。
2、事务的分类:
- 扁平事务
- 带有保存点的扁平事务
- 链式事务
- 嵌套事务
- 分布式事务
3、事务处理原则:
保证所有事务都作为 一个工作单元 来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交( commt ),那么这些修改就水久 地保存下来,要么数据库管理系统将 放弃 所作的所有 修改 ,整个事务回滚( rollback )到最初状态。
4、事务的ACID特性
1、原子性
原子性是指事务是一个不可分割的工作单位,要么全部提交,要么全部失败回滚。即要么转账成功,要么转账失败,是不存在中间的状态。如果无法保证原子性会怎么样?就会出现数据不一致的情形,A账户减去100元,而B账户增加100元操作失败,系统将无故丢失100元。
2、一致性
根据定义,一致性是指事务执行前后,数据从一个 合法性状态 变换到另外一个 合法性状态。这种状态是 语义上的而不是 语法 上的,跟具体的业务有关。
那什么是合法的数据状态呢?满足 预定的约束 的状态就叫做合法的状态。通俗一点,这状态是由你自己来定义的(比如满足现实世界中的约束)。满足这个状态,数据就是一致的,不满足这个状态,数据就是不一致的!如果事务中的某个操作失败了,系统就会自动撤销当前正在执行的事务,返回到事务操作之前的状态。3、隔离性
事务的隔离性是指一个事务的执行 不能被其他事务干扰,即一个事务内部的操作及使用的数据对 并发 的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
4、持久性
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是水久性的,接下来的其他操作和数据库故障不应该对其有任何影响。
持久性是通过 事务日志 来保证的。日志包括了 重做日志 和 回滚日志。当我们通过事务对数据进行修改的时候,首先会将数据库的变化信息记录到重做日志中,然后再对数据库中对应的行进行修改。这样做的好处是,即使数据库系统崩溃,数据库重启后也能找到没有更新到数据库系统中的重做日志,重新执行,从而使事务具有持久性。
5、事物的状态
- 活动的
- 部分提交的
- 失败的
- 终止的
- 提交的
6、事物的隔离级别
1、数据并发问题
- 脏写
- 脏读
- 不可重复读
- 幻读
2、SQL中四种隔离级别
严重性排序:
脏写 > 脏读 > 不可重复读 > 幻读
- READ UNCOMMITTED:读未提交,在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。不能避免脏读、不可重复读、幻读。
- READ COMMITTED:读已提交,它满足了隔离的简单定义: 一个事务只能看见已经提交事务所做的改变。这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。可以避免脏读,但不可重复读、幻读问题仍然存在。
- REPEATABLE READ:可重复读,事务A在读到一条数据之后,此时事务B对该数据进行了修改并提交,那么事务A再读该数据,读到的还是原来的内容。可以避免脏读、不可重复读,但幻读问题仍然存在。这是MySQL的默认隔离级别。
- SERIALIZABLE:串行化事务,对该表执行插入、更新和删除操作。所有的并发问题都可以避免,但性能十分低下。能避免脏读、不可重复读
隔离级别 脏读可能性 不可重复读可能性 幻读可能性 加锁读 READ UNCOMMITED YES TES TES NO READ COMMITED NO YES YES NO REPEATABLE READ NO NO YES NO SERIALIZABLE NO NO NO YES 隔离级别的代码操作
# 查看当前的隔离级别 show variables like 'transaction_isolation'; select @@transaction_isolation; # 如何让设置隔离级别 SET [GLOBAL|SESSION] TRANSACTION IOSLATION LEVEL 隔离级别; SET [GLOBAL|SESSION] TRANSACTION_IOSLATION = 'READ-UNCOMMITTED';
二、如何使用事务
1、事务的提交方式
# 关于自动提交的变量 autocommit SHOW VARIABLES LIKE 'autocommit'; # 管理自动提交的变量 SET autocommit=OFF/ON;
2、事务的显示操作
# 启动一个事务 begin / start transaction; # 在事务中创建指定名称的保存点 savepoint pt1; # 让事务回滚到指定保存点。 rollback to pt1; # 直接让事务回滚到最开始。 rollback; # 提交事务,提交事务后就不能回滚了。 commit;
start transaction 后面可以跟随修饰符
- READ ONLY:只读
- READ WRITE:可读可写(默认)
- WITH CONSISTENT SNAPSHOP:启动一致性读
3、事务的隐式提交
- 所有的DDL: 当你在执行 DDL 语句前,事务就已经提交 了。这就意味着带有 DDL 语句的事务将来没有办法 rollback。
- 所有的DCL: 当然,除了 GRANT 和 REVOKE 之外,其他的创建、更新或者删除用户的操作也会导致事务隐式提交。主要有:
- REATE USER…
- DROP USER…
- ALTER USER…
- SET PASSWORD…
- 新事务的开启:如果一个事务还没提交,你又开启了一个新的事务,那么此时前一个事务也会隐式提交。
- 各种锁操作: 给表上锁、解锁也会导致事务隐式提交
- 从机的操作: 我们在从机上执行的一些操作如 start slave 、 stop slave 、 reset slave 以及 change master to 等语句也会隐式提交事务。
- 其他表操作: 其他的一下操作如刷新权限(flush privileges)、优化表(optimize table)、修复表(repair table) 等操作,也会导致事务的隐式提交
三、MySQL事务日志
1、日志的分类
- 事务的隔离性由
锁机制
实现。- 而事务的原子性、一致性和持久性由事务的 redo 日志和 undo 日志来保证。
- REDO LOG 称为
重做日志
,提供再写入操作,恢复提交事务修改的页操作,用来保证事务的持久性。- UNDO LOG 称为
回滚日志
,回滚行记录到某个特定版本,用来保证事务的原子性、一致性。
2、REDO LOG
InnoDB 存储引擎是以页为单位来管理存储空间的。在真正访问页面之前,需要把在磁盘上的页缓存到内存中的 Buffer Pool 之后才可以访问。所有的变更都必须先更新缓冲池中的数据,然后缓冲池中的脏页会以一定的频率被刷入磁盘(checkPoint 机制),通过缓冲池来优化 CPU 和磁盘之间的鸿沟,这样就可以保证整体的性能不会下降太快。
1、好处、作用
- redo日志降低了刷盘频率
- redo日志占用的空间非常小
- 存储表空间ID、页号、偏移量以及需要更新的值,所需的存储空间是很小的,刷盘快。
2、特点
- redo日志是顺序写入磁盘的:在执行事务的过程中,每执行一条语句,就可能产生若干条redo日志,这些日志是按照产生的顺序写入磁盘的,也就是使用顺序IO,效率比随机IO快。
- 事务执行过程中,redo log不断记录:redo log 跟bin log 的区别,redo log 是存储引擎层产生的,而bin log是 数据库层产生的。假设一个事务,对表做10万行的记录插入,在这个过程中,一直不断的往redo log顺序记录,而bin og不会记录,直到这个事务提交,才久写入到bin log文件中
3、组成
- 重做日志缓冲 (redo log buffer),保存在内存中,是易失的。由innodb_log_buffer_size变量指定
- 重做日志文件 (redo log file),保存在硬盘中,是持久的。
- 刷盘频率,innodb_flush_log_at_trx_commit 参数
- 设置为0 :表示每次事务提交时不进行刷盘操作(系统默认 master thread 每隔 1s 进行一次重做日志的同步);
- 设置为1 :表示每次事务提交时都将进行同步,刷盘操作(默认值);
- 设置为2 :表示每次事务提交时都只把 redo log buffer 内容写入 page cache,不进行同步。由操作系统自己决定什么时候同步到磁盘文件;
4、执行步骤
3、UNDO LOG
redo log 是事务持久性的保证,undo log 是事务原子性的保证。在事务中更新数据的前置操作其实是要先写入一个 undo log。
1、好处、作用
- 回滚数据,注意,只是将数据库逻辑的恢复到原来的样子了,但数据页可能完全不同
- 多版本并发控制,在多线程时,可以通过undo日志读取之前版本的行信息,从而实现非锁定读取。
2、小结
- undo log 是逻辑日志,对事务回滚时,只是将数据库逻辑地恢复到原来的样子。
- redo log 是物理日志,记录的是数据页的物理变化,undo log 不是 redo log 的逆过程。
四、锁