MySQL 事务

日常开发中,很多操作,不是通过一个SQL就能完成的,往往需要多个SQL配合完成
当执行多个SQL操作的时候,如果中间出现了特殊的情况(程序崩溃,网络断开,主机掉点了...),可能就会出现,前面的SQL执行成功,后面的SQL执行失败了,这时就需要事务

事务:把多个操作,打包成一个整体

使用事务

sql 复制代码
start transaction;
...
rollback/commit;

事务的基本特性

  • 原子性
  • 一致性
  • 持久性
  • 隔离性

原子性

能够保证,这个整体要么都执行成功,要么就一个都不执行,能够有效避免,部分执行,部分未执行,产生的一些"中间状态引起的问题",把多个操作,打包成一个整体,称为"原子性"

(这里并非一个都不执行,而是事务可以保证当执行到某一条的时候出现问题了,数据库就能自动的把前面SQL造成的影响,给恢复回去,恢复如初,看起来就好像一条SQL都没执行的样子,这里的"翻新"的操作,称为**"回滚"(rollback)**)

事务的原子性 就是通过回滚机制来保证的,为了实现回滚机制,数据库会在执行事务的时候,记录日志,println...就是日志,数据库的日志是写入到硬盘的文件中了,当事务最终都执行完毕,中间没有差错,这些记录就可以不要了,但是如果执行事务的过程中出现问题了,MySQL就可以根据日志中记录的内容来进行恢复操作了:

之前进行的新增 操作,就把数据删除

之前进行的删除 操作,就把数据新增上来

之前进行的修改操作,就把数据改回去

之前进行的查询操作,不影响,不需要进行任何恢复行为

  1. 程序崩溃:应用程序(Java写的程序),数据库是正常的,直接进行回滚操作即可
  2. 系统崩溃:MySQL服务器崩溃,挂了的时候无法立即进行回滚,数据库重新启动的时候,就能够发现上次有个事务出问题了,按照之前记录日志进行回滚
  3. 网络断开:与程序崩溃一致,等待网络连接,直接进行回滚
  4. 主机断电:与系统崩溃处理方法一致

一致性

执行事务之前,和执行事务完毕之后数据是一致的

一致性也与回滚有关,一旦触发了回滚,回滚回去的数据得是对的,如果顺利执行没有触发回滚,数据也是要符合要求的

持久性

把数据存储在硬盘上,此处的持久,程序重启/主机重启,数据依然能存在(不仅仅是数据库,但凡见到"持久性"都是这个意思)

不丢失 = 持久性 + 一致性

执行事务对数据库产生的修改,就会在硬盘上持久保存,重启之后仍然存在

隔离性

隔离性描述的是数据库并发(多个客户端,同时给服务器,发起事务)执行事务时,产生的情况比较复杂,若是多个客户端操作的是同一张表,则要保证:尽可能保证不出错,并且提高效率,隔离性就是要一起处理的情况下不出错 + 效率提高

脏读问题

MySQL服务器读到的是个临时数据,临时数据可能会被随时修改掉

数据库中,如果有事务A和事务B,事务A针对某个表做出了一些修改,在事务A提交之前事务B就对这里的数据进行了读取,最终就可能出现A后续的操作又把上述数据进行了修改,导致最终B读到的数据和A提交的数据,是不同的

如何解决脏读问题?对写操作加锁,也就是说只有一个事务才能对某张表修改,写操作进行时其他事务不得进行写操作,这种方式就可以解决脏读问题,引入写加锁之后,执行A的过程中,B就不能执行了,要等待,这就相当于降低了"并发能力",也就会降低数据库服务器的处理效率,提高了"隔离性",也提高了数据的准确性

不可重复读问题

存在三个事务ABC,事务A针对数据进行修改,提交,接下来事务B进行读取数据(事务B多个SQL都要进行读操作),在执行B的过程中又有一个事务C,又针对数据进行了修改,就会使B里面的不同读操作,读出来的结果不一样

如何解决不可重复读问题?在写操作加锁的情况下,给读操作也加锁

  • 写操作加锁:我写的时候,别人不能读
  • 读操作加锁:别人读的时候,我也不能写

此时再次引入锁,就会使"并发程度"进一步降低,效率也随之降低,"隔离性"又进一步提高,数据的准确性也会提高,这个时候,ABC都不能并发了

幻读问题

此时已经进行了读操作和写操作,幻读问题和不可重复读问题类似,事务B读的过程中,事务C没有修改数据内容,而是修改了"结果集",导致B内部不同的读操作读到的结果集合不同

如何解决幻读问题?串行化:所有的事务都是串行执行的,此时就不会有这样的问题

MySQL事务的隔离性具体是怎么体现的?

  • read uncommitted:允许读取其他事务未提交的数据 =>

脏读 + 不可重复读 + 幻读 并发程度最高,隔离性最低

  • read committed:只能读取其他事务提交后的数据 =>

解决了脏读,存在不可重复读 + 幻读 并发程度降低,隔离性提高

  • repeatable read:针对读操作和写操作都加锁了 =>

解决了脏读 + 不可重复读,存在幻读 并发程度又降低,隔离性又提高

  • 串行化(serializable):所有的事务都是串行执行的 =>

解决了脏读 + 不可重复读 +幻读 并发基本没有,隔离性最高

修改MySQL配置文件my.ini,使服务器处于某个隔离级别中来运行;比如先做做一个和钱有关的系统,可以设置成串行化;做一个短视频点赞系统,就可以设置成读未提交,追求最大的效率

以上为事务常见的特性以及重要问题解决方案,下一篇博客介绍JDBC!

相关推荐
D_J_Dragon2 小时前
Spring Security基于token的极简示例
java·spring boot·后端·spring
Autter_A33 小时前
MySQL的半同步模式
android·mysql·github
Flying_Fish_roe4 小时前
Redis的内存淘汰策略-volatile-ttl
数据库·redis·缓存
小冰子X4 小时前
Redis 常用命令
数据库·redis·缓存
Ting-yu4 小时前
零基础学习Redis(8) -- list类型命令使用
数据库·redis·学习
0712210984 小时前
在项目中使用 redis存储 数据,提高 项目运行速度
数据库·redis·缓存
Lill_bin4 小时前
Redisson与Redis分布式锁
开发语言·数据库·redis·分布式·微服务·云原生·架构
曹申阳4 小时前
02. 开发前准备,Docker安装MySQL,Redis
redis·mysql·docker
zero_one_Machel5 小时前
leetcode5最长回文子串
java·数据结构·算法
qq_2518364575 小时前
基于web旅游信息平台的设计与实现
数据库·microsoft·旅游