1.什么是事务
一个事务由一条或多条sql语句组成,这些语句要么全部执行成功,要么全部执行失败
2.为什么需要事务?
保证数据的完整性和一致性
3.事务的特性
-
原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
-
一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
-
隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
-
持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
4.事务管理的对象
DML语句(像insert replace delete)和DCL(像grant)语句,DDL(像create)不受影响
5.输入一条sql语句背后发生了什么?
用户在客户端连接器输入一条sql语句,通过连接池连接到SQL接口
解析器解析命令语句,同时判断是否有权限
查询优化器查看是否有索引,没有则全盘查看
找到目标后先去缓存中查找,没有再去磁盘查找。
6.commit与rollback
commit:将内存中的数据存储到磁盘中,持久化。
insert --》内存中的数据--》innodb--》buffer中的数据--》磁盘
rollback:回滚到事务开始前的阶段
savepoint a 在事务中创建一个回滚点a
savepoint b 在事务中创建一个回滚点b
rollback to b 回滚到b这个阶段
rollback to a 回滚到a这个阶段,不过不能再回到b阶段
7. autocommit
mysql中的系统变量前都会带两个@@,用户定义的变量带一个@符号
@@autocommit:管理事务的提交,为1时事务自动提交commit,为0时需要用户人为输入commit或rollback提交 。
8.事务的开始
隐式开始:程序的第一条DML语句执行时或者在COMMIT或ROLLBACK语句执行后第一条DML语句时,自动开始一个新的事务
显示开始:发出BEGIN或者START TRANSACTION语句,该语句会自动关闭自动提交,当事务结束后autocommit变量自动恢复为原来的值
9.实例讲解
一、rollback的使用
这一个只有t0表的库,输入start transaction开始一个事务,关闭自动提交
创建一个t1表
可以看到数据已经存到磁盘中,应为create语句属于DDL语句,不受事务影响
插入一条数据,并且设置一个回滚点first
插入第二条数据,同时设置回滚点second
此时表中有2条数据
将表中的数据删除
回滚到second点,可以看到表中的两条数据恢复了
回滚到first点,数据恢复到只剩一条。
输入rollback,恢复到事务开始最初没有数据的状态
同时一个事务也结束了
二、事务的运行
事务开始
在表中插入三条数据
在另一条线程B中我们看不到一条数据
输入commit提交
可以在线程B中看到
我们继续开启一个线程,并且修改第一条数据
通过线程B看到第一条数据还是没修改的
在线程B中操作修改第一条数据,卡住了,进入了排队状态,按ctrl+c退出来
修改第二条数据
在线程B中为
在我所使用的线程A中
所以B线程的操作没有影响到A线程,B线程在表中添加一条数据
A中依然没变,这是因为A中事务默认开启了可重复读。
在A中输入commit提交后,线程A和B都显示一致
这就是事务的运行只有语句全部执行成功或者失败的原因,当我输入commit后,线程A的事务执行完毕,所有语句执行成功,即replace into t1(id, name) values(1,'dsg');语句和一系列select语句执行成功,效果相当于对线程B修改后的表t1执行了replace into t1(id, name) values(1,'dsg');语句,因为线程B执行的输入一句就是执行一个事务,而线程A的事务最后在执行完成。
中途线程B修改t1表的第一条数据失败的原因:因为mysql会给事务操作过的行加上行锁,别的线程不允许操作这行,但事务没操作过的行不受影响。
行锁相比于表锁极大地提高了mysql的性能。
脏数据:已修改但未提交的数据
脏读:一个事务读到了另一个事务未提交的数据