MYSQL事务特点


事务的定义:

一个事务是由一条或者多条对数据库操作的SQL语句所组成的一个不可分割的单元,只有当事务中的所有操作都正常执行完了,整个事务才会被提交给数据库;如果有部分事务处理失败,那么事务就要回退到最初的状态,因此,事务要么全部执行成功,要么全部失败。

事务的特征(ACID):

事务的原子性(Atomic)

事务是一个不可分割的单元,事务必须具有原子性,即要么全部执行,要么全部不执行,不允许部分执行

事务的一致性(Consistency)

一个事务执行之前和执行之后,数据库中的数据必须保持一致性状态

事务的隔离性(Isolation)

当两个或者多个事务并发执行时,未来保证数据的安全性,当一个事务内操作和其他事务的操作需要起到隔离起来,不被其他正在执行的事务所看到,隔离性使得每个事务的更新在提交之前,对于其他事务是不可见的

事务的持久性(Durability)

事务完成之后,数据库需要保证当前事务的修改时永久性的,即使数据库因为故障出错,也应该恢复数据

事务的使用

1、查看事务:select @@autocommit

通过select @@autocommit;;可以查看事务状态
默认为1:表示事务是自动提交 0表示手动提交

select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            1 |
+--------------+

2、事务设置:set autocommit

使用set autocommit=0; 进行事务手动提交

set autocommit =0;
Query OK, 0 rows affected (0.01 sec)

3、事务操作

3.1、开启事务:begin或start transaction

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

3.2 事务提交:commit

当一个或者多个SQL组成的事务需要提交时,就通过commit来操作

3.3、事务回滚:rollback

如果执行的过程中有部分事务执行失败,回滚到事务最初的状态

3.4、保存点:savepoint point1

savepoint point1;设置一个名称为point1的保存点
rollback to point1;事务回滚到指定的point1点,而不是最初的保存点

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into student values(1008,'永恩','g','2019-03-12','8888888',1);
Query OK, 1 row affected (0.38 sec)

mysql> savepoint point1;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into student values(1009,'瑞文','g','2019-03-12','32150086',1);
Query OK, 1 row affected (0.00 sec)

mysql> rollback to point1;
Query OK, 0 rows affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

mysql> select * from student;
+------+--------------+------+------------+-----------+------+
| s_id | s_name       | sex  | birthday   | QQ        | c_id |
+------+--------------+------+------------+-----------+------+
| 1001 | 盖伦         | g    | 2010-10-25 | 857857857 |    3 |
| 1002 | 赵信         | g    | 2010-10-25 | 74174171  |    3 |
| 1003 | 嘉文四世     | g    | 2010-10-25 | 852852852 |    3 |
| 1004 || m    | 2017-05-20 | 520520520 |    1 |
| 1005 || g    | 2017-05-20 | 521521521 |    1 |
| 1006 | 亚索         | g    | 2013-01-20 | 111111111 |    1 |
| 1007 | 塞恩         | g    | 2010-01-20 | 996996996 |    2 |
| 1008 | 永恩         | g    | 2019-03-12 | 8888888   |    1 |
+------+--------------+------+------------+-----------+------+
8 rows in set (0.00 sec)

我们可以看到1009 瑞文没有添加成功 因为我们回滚到了添加瑞文之前了所以没有添加成功。

4、查看隔离级别:select @@transaction_isolation;

select @@tx_isolation;(久版本)
select @@transaction_isolation;(新版本)

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)

并发事务问题

在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对统一数据进行操作)。并发虽然是必须的,但可能会导致以下的问题:

1、脏读(Dirty read)

A事务读取了B事务尚未提交的更改数据,并在这个读取的脏数据上进行操作。如果这时B事务恰巧进行了回滚事务,那么A事务读取的事务是不被承认的

2、不可重复读(Unrepeatableread)

在同一个事务中,同一个读操作对同一个数据的前后两次读取产生了不同的结果,这就是不可重复读。

3、幻读(Phantom read)

幻像读是指在同一个事务中以前没有的行,由于其他事务的提交而出现的新行。

不可重复度和幻读区别:

不可重复读一般针对的是行级别的数据的更改(修改),不可重复读的重点是修改
幻象读一般针对表级别的新增数据,在统计事务中,两次读取的数据统计不一致,幻读的重点在于新增或者删除。

事务隔离级别

1、READ-UNCOMMITTED(读取未提交)

最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。

2、READ-COMMITTED(读取已提交)

允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。

3、REPEATABLE-READ(可重复读)

对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。

4、SERIALIZABLE(可串行化)

最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
在这里插入图片描述
MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)。我们可以通过SELECT @@tx_isolation;命令来查看

mysql> SELECT @@tx_isolation;

因为隔离级别越低,事务请求的锁越少

事务原理

1、MVCC多版本控制

MVCC (Multiversion Concurrency Control),即多版本并发控制技术
读锁:也叫共享锁、S锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S 锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。
写锁:又称排他锁、X锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。
表锁:操作对象是数据表。Mysql大多数锁策略都支持(常见mysql innodb),是系统开销最低但并发性最低的一个锁策略。事务t对整个表加读锁,则其他事务可读不可写,若加写锁,则其他事务增删改都不行。
行级锁:操作对象是数据表中的一行。是MVCC技术用的比较多的,但在MYISAM用不了,行级锁用mysql的储存引擎实现而不是mysql服务器。但行级锁对系统开销较大,处理高并发较好。

MVCC实现原理

1.对于数据表的每条记录其实是这样的:
在这里插入图片描述
1.DATA_TRX_ID:标记了最新更新这条行记录的transaction id,每处理一个事务,其值自动+1,大小为6字节;
2.DATA_ROLL_PTR:指向当前记录项的undo log记录,找之前版本的数据就是通过这个指针;
3.DB_ROW_ID:行标识(隐藏自增ID)当由innodb自动产生聚集索引时,聚集索引包括这个DB_ROW_ID的值,否则聚集索引中不包括这个值.,这个用于索引当中,大小为6字节;
2.当我针对一条记录执行update操作,则会
针对表某个记录加入排他锁
把该记录原本的最新记录拷贝到undo log日志中,DB_TRX_ID和DB_ROLL_PTR不变
通过修改生成新的记录,并包含新的DB_TRX_ID和DB_ROLL_PTR
通过往复操作也就会针对此记录形成一个版本链 如下图:
begin->用排他锁锁定该行->记录redo log->记录undo log->修改当前行的值,写事务编号,回滚指针指向undo log中的修改前的行
链的最顶端保存了最新的一条数据,之后通过指针指向undolog日志;

在这里插入图片描述

MVCC特点:

每行数据都存在一个版本,每次数据更新时都更新该版本
修改时Copy出当前版本随意修改,各个事务之间无干扰
保存时比较版本号,如果成功(commit),则覆盖原记录;失败则放弃copy(rollback)
就是每行都有版本号,保存时根据版本号决定是否成功,听起来含有乐观锁的味道,而Innodb的实现方式是:
事务以排他锁的形式修改原始数据
把修改前的数据存放于undo log,通过回滚指针与主数据关联
修改成功(commit)啥都不做,失败则恢复undo log中的数据(rollback)

2、事务日志

在MVCC中,要保证事务的执行用到了undolog,事务要保证ACID的完整性必须依靠事务日志做跟踪,每一个操作在真正写入数据数据库之前,先写入到日志文件中如要删除一行数据会先在日志文件中将此行标记为删除,但是数据库中的数据文件并没有发生变化。在事务引擎上的每一次写操作都需要执行两遍如下过程:
1、先写入日志文件中 写入日志文件中的仅仅是操作过程,而不是操作数据本身,所以速度比写数据库文件速度要快很多。
2、然后再写入数据库文件中 写入数据库文件的操作是重做事务日志中已提交的事务操作的记录。

2.1、redo log

在innoDB的存储引擎中,事务日志通过重做(redo)日志和innoDB存储引擎的日志缓冲(InnoDB Log Buffer)实现。事务开启时,事务中的操作,都会先写入存储引擎的日志缓冲中,在事务提交之前,这些缓冲的日志都需要提前刷新到磁盘上持久化,这就是DBA们口中常说的“日志先行”(Write-Ahead Logging)。
InnoDB 的 redo log 是固定大小的,比如可以配置为一组 4 个文件,每个文件的大小是 1GB,那么这块日志总共就可以记录 4GB 的操作。

2.2、undo lo

undo log主要为事务的回滚服务。在事务执行的过程中,除了记录redo log,还会记录一定量的undo log。undo log记录了数据在每个操作前的状态,如果事务执行过程中需要回滚,就可以根据undo log进行回滚操作。单个事务的回滚,只会回滚当前事务做的操作,并不会影响到其他的事务做的操作。

redo log其实保证的是事务的持久性和一致性,而undo log则保证了事务的原子性。
undo log是逻辑日志,可以理解为:
当delete一条记录时,undo log中会记录一条对应的insert记录
当insert一条记录时,undo log中会记录一条对应的delete记录
当update一条记录时,它记录一条对应相反的update记录

2.3、binlog

关于mysql主从同步很重要,随着系统应用访问量逐渐增大,高并发下通常会采用mysql集群,主库和从库之间的数据是如何同步,其实就是通过binlog主从同步binlog来实现的。
▪ Binlog是server层的日志,主要做mysql功能层面的事情
▪ 与redo日志的区别:

redo是innodb独有的,binlog是所有引擎都可以使用的。
redo是物理日志,记录的是在某个数据页上做了什么修改,redo是循环写的,空间会用完,
binlog是逻辑日志,记录的是这个语句的原始逻辑。binlog是可以追加写的,不会覆盖之前的日志信息。

主从复制原理

mysql主从复制需要三个线程,master(binlog dump thread)、slave(I/O thread 、SQL thread)。master
(1)binlog dump线程:当主库中有数据更新时,主库就会根据设置的binlog格式,将更新的事件类型写入到主库的binlog文件中,此时主库会创建log dump线程通知slave有数据更新,当I/O线程请求日志内容时,会将此时的binlog名称和当前更新的位置同时传给slave的I/O线程。
slave
(2)I/O线程:该线程会连接到master,向log dump线程请求一份指定binlog文件位置的副本,并将请求回来的binlog存到本地的relay log中,relay log和binlog日志一样也是记录了数据更新的事件,它也是按照递增后缀名的方式,产生多个relay log(host_name-relay-bin.000001)文件,slave会使用一个index文件( host_name-relay-bin.index)来追踪当前正在使用的relay log文件。
(3)SQL线程:该线程检测到relay log有更新后,会读取并在本地做redo操作,将发生在主库的事件在本地重新执行一遍,来保证主从数据同步。此外,如果一个relay log文件中的全部事件都执行完毕,那么SQL线程会自动将该relay log 文件删除掉。
下面是整个复制过程的原理图:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值