事务是一组操作的集合,他是一个不可分割的工作单位,事务会把所有的操作作为也给整体一起向整体提交或撤销请求,即这些操作要么成功要么失败。
默认mysql的事务时自动给提交的,也就是当执行一条DML语句,MySQL会立即隐式的提交事务
比如:在银行转账中,张三原本有2000元,李四原本有2000元,张三要给李四转账1000元,在张三转账完成时系统发生故障,这1000块钱到不了李四的账户上,那么张三的1000元应该返回到张三账户,这个现象就可以使用事务。
还是上面转账的例子:
张三给李四转账1000元,这里我们需要查看一下事务的提交类型是手动提交还是自动提交,在navicat中使用命令:1为自动提交,0为手动提交
select @@autocommit;
set @@autocommit=0
模拟转账:首先要开启事务使用命令
start transaction 或begin
BEGIN//开启事务
select * from account where name ='张三';
update account set money =money-1000 where name ='张三';
update account set money =money+1000 where name ='李四';
同时执行上面三行sql语句,在执行update account set money =money+1000 where name ='李四’出错,应该让事务进行回滚,执行
roolback
这样就会在张三转账1000元到李四账户上,如果有异常发生还能退回到李四的账户中。
为什么不直接提交事务?因为转账过程中已经有异常了,提交完事务就会应该张三的账户金额。
可以理解为如果遇到异常之后,要把事务进行回滚。
注意:
在事务中,所有的修改操作都会被保存在内存中的临时区域中,称为事务日志(transaction log)。这包括插入、更新和删除等操作。只有在事务提交后,这些修改才会被写入磁盘上的实际数据文件,从而影响数据库表中的数据。
如果你在执行事务期间没有进行事务提交或回滚操作,那么数据库表中的数据将不会发生改变。这是因为事务的ACID属性之一是隔离性,它确保一个事务在提交之前对其他事务是不可见的。
如果你想要查看在事务中所做的修改,可以使用事务的查询功能,在事务还未提交之前查询数据。这样可以查看事务内部的临时状态,但对其他事务是不可见的。
需要注意的是,如果你的会话意外终止或发生异常,事务可能会自动回滚,导致在事务中做的修改不会被持久化到数据库中。因此,在执行事务操作时,务必小心处理事务提交和回滚的逻辑,以确保数据的一致性和完整性。
事务并发问题会在事务隔离级别中通过例子进行详细解析,这里先给出一个宏观的概念
一个事务读到另外一个事务还没有提交的数据
一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读
在黄色部分:执行查询语句之后,事务b执行了更新操作并提交,黄色部分继续执行和第一步一样的查询语句,那么他们读取的数据不一致,这个现象就是不可重复读
一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这样数据已经存在,好像出现了幻影
select @@TRANSACTION_ISOLATION
设置隔离级别:session为当前会话,global所有会话都有效
set session/global transaction isolation level 隔离级别名称
事务隔离级别越高,数据越安全,但是性能越低
这个案例里面会说明事务并发问题
模拟两个事务:事务A使用read uncommitted,查询数据库中最原始的数据
事务B使用默认的事务,开启事务并对数据进行更新操作,此时并未提交事务:
接着在去A事务中查询数据库中的数据:
发现数据已经发生了变化,在事务B未提交的情况下,事务A读取到了事务B未提交的数据,这里就是脏读
模拟两个事务:事务A使用read committed,查询数据库中原始的数据:
事务B使用对数据库中的数据执行更新操作,此时并未提交数据
接着去事务A中查询数据:并没有因为事务B修改了数据,而查到数据,解决了脏读的问题
事务B执行提交操作:
再去事务A中查看数据:数据发生了更改、
还是上面的操作步骤,在事务A第一次和最后一次执行相同的sql语句时,发现查询出来的数据是不一致的,这个现象就是不可重复读。
模拟两个事务:事务A使用repeatable read,查询初始的数据库内容;
事务B执行更新数据库操作,并提交提交事务,
事务A去查询数据库中数据,发现并没有因为事务B提交了数据查询的数据而发生了不一样的问题
当A事务提交之后,就可以查看到事务B的更新数据
幻读
模拟两个事务,在A事务中查询id为3的数据,没有查到,说明该数据库中没有该行数据,
在事务B中去开启事务并,插入数据id为3的内容,并提交事务
在A事务的角度来说,数据库中没有id为3的数据那么我就进行插入数据,系统提示已经有该行数据了
这个现象就叫幻读
如何解决这个问题,使用serializable;
模拟连个事务,在A使用使用该隔离级别,开启一个事务,并查询一个不存在数据
在B事务中进行插入该数据,会发现插入不进去,最后会报错
做例子发现,前提是数据库中没有id为5、6的数据,当事务B进行插入6时,此时事务A查询的是5,那么此时事务B也插入不进去,除非此时事务A提交查询操作
也就是A事务正在操作,B事务就得等,事务A提交之后,事务B才能执行插入的操作
原子性、一致性、持久性主要是由redo log和undo log日志来保证,
隔离性主要是由锁、MVCC来保证
redo log:用来保证事务的持久性
重做日志,记录的是事务提交时数据页的物理修改,是用来实现事务的持久性。该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo log file),前者是在内存中, 后者在磁盘中。当事务提交之后会把所有修改信息都存到该日志文件中,用于在刷新脏页到磁盘,发生错误时,进行数据恢复使用。
如果在脏页刷新到磁盘的过程中,出现错误,这时候其实已经告诉用户事务提交成功,那么这个时候持久性就没有得到保证。这个时候就需要redo log
当客户端提交了增删改操作之后,这些命令会先存到redo log buffer中,在redo log buffer中就会去记录数据页的变化,当提交事务的时候,就会直接把redo log buffer中的数据页的变化,刷新到磁盘中,持久化保存在磁盘中,等过一段时间进行脏页刷新的时候了,那么可以通过redo log进行回滚
MySQL 是一个非常流行的关系型数据库管理系统,支持事务的处理。在 MySQL 中,事务是相互独立的一组操作,它们被视为单个逻辑工作单元。下面就MySQL中事务的结尾总结进行介绍。
首先,在 MySQL 中,事务的结尾总结通常包括对整个过程的评估和分析。我们需要考虑到整个过程中出现的挑战、成功和失败,以及我们从中学到的教训。通过这样的分析,我们可以更好地了解如何避免未来类似问题,以及如何在类似情况下更好地应对。
其次,在 MySQL 中,我们需要确认所有的任务都已经完成。这包括确认是否有任何未完成的工作或遗漏的细节。在确认所有事项都已经完成后,我们可以开始提交事务并关闭连接。这有助于保证数据完整性和一致性。
除此之外,在 MySQL 中,事务的结尾总结也是向他人汇报事务进展和结果的机会。我们需要准备好相关的文档和材料,并向相关人员提供透明、全面的报告。这有助于促进信息共享和团队协作,同时也能够帮助我们更好地管理我们的时间和资源。
最后,我们需要总结一下整个过程中取得的成果和收获。这包括任何收益、效益或其他利益,以及我们在过程中获得的知识和经验。通过这种方式,我们可以更好地了解我们在事务中的表现,并从中汲取教训,以帮助我们更好地处理未来的事务。
总之,在 MySQL 中,事务是非常重要的,对于数据的完整性和一致性有着至关重要的作用。通过评估分析、确认任务完成、汇报结果和总结收获,我们可以更好地管理 MySQL 中的事务,并取得更好的结果。