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!

相关推荐
用户40315986396632 分钟前
表达式并发计算
java·算法
SimonKing14 分钟前
告别System.currentTimeMillis()!Java高精度计时最佳实践
java·后端·程序员
Dcs14 分钟前
JUnit 5架构如何用模块化颠覆测试框架?
java
Dubhehug18 分钟前
8.数据库索引
数据库·mysql·索引·索引分类·索引优缺点
肉肉不想干后端18 分钟前
gRPC服务架构整合springboot部署实践指南
java
冬夜戏雪32 分钟前
阿里云ubuntu安装mysql docker容器(拉,运行,测试完整版)
mysql·ubuntu·阿里云
满分观察网友z35 分钟前
告别CRUD Boy!SQL子查询:从头疼到真香的进化之路
数据库·后端
天天摸鱼的java工程师35 分钟前
volatile关键字实战指南:八年Java开发者详解五大应用场景
java·后端
楼兰胡杨38 分钟前
MySQL 更新字段的值为当前最大值加1
mysql
赤鸢QAQ39 分钟前
Qt小组件 - 2(布局)瀑布流布局,GridLayout,FlowLayout
开发语言·数据库·qt