
之前面试的时候还真的有一个面试官问过我什么是事务事务说人话就是把多个数据库操作打包成一个“不可分割的整体”要么全成功要么全失败并回滚到最初状态绝对不会出现“只做了一半”的情况。以生活中最经典的银行转账举个例子那是再合适不过了。且看A给B转100块钱这一笔转账业务其实是由两步独立的数据库操作组成的A的账户扣100块B的账户加100块这两步必须同时成功、一起生效。如果A扣了钱B没收到或者B收到了钱A没扣那银行就乱套了。事务的四大特性用银行转账的例子加深理解特性解释银行转账例子原子性Atomicity要么全做要么全不做就像“原子”一样不可分割A扣钱和B加钱必须同时成功不能A扣了B没加一致性Consistency事务前后数据要保持“一致”总金额不变转账前A有1000B有0总和是1000转账后A有900B有100总和还是1000隔离性Isolation多个事务同时执行时互相不干扰就像“隔离开”一样两个转账操作同时改A的账户不能互相影响不然钱就不对了持久性Durability事务提交后数据就永久保存了就算数据库挂了也不会丢转账成功后就算银行服务器断电重启A和B的钱数也不会变隔离级别为什么要有隔离级别呢如果多个事务同时执行没有隔离的话会出现3个问题脏读脏读就是读到了别人还没提交的数据。比如A转给B100块还没提交B就查到自己多了100块结果A回滚了B白高兴一场。不可重复读不可重复读的意思是同一个事务里两次读同一条数据的结果是不一样的。比如A查自己有1000块中间B转给了A100块提交了A再查就变成1100了。幻读幻读就是同一个事务里两次查的数量不一样。比如A查账户里有10条记录中间B插了一条提交了A再查就变成11条了就像“幻觉”一样。这么看不可重复读和幻读是由别的事务提交后导致的错误而脏读是读到了别人还没提交的临时数据。那不可重复读和幻读两者的区别在哪呢不可重复读是盯着一条记录看发现这条记录的内容变了。而幻读是盯着一堆记录数看发现总数量变了。类比一下就是不可重复读是你看自己的银行卡余额钱数变了而幻读是你数银行有多少张卡卡的数量变了。隔离级别解决的问题解释读未提交Read Uncommitted啥都解决不了能读到别人没提交的数据脏读、不可重复读、幻读都有一般不用读已提交Read Committed脏读只能读到别人提交后的数据但会有不可重复读、幻读可重复读Repeatable Read脏读、不可重复读Spring默认的隔离级别。同一个事务里两次读同一个数据一样但会有幻读MySQL InnoDB用MVCC解决了幻读串行化Serializable所有问题事务一个接一个执行就像“排队”一样性能最差一般不用传播行为传播行为就是当一个事务方法调用另一个事务方法时这两个事务该怎么协作是直接加入原事务还是新建一个独立的事务还是先挂起原事务等新事务执行完再继续以下是3 个常用的传播行为:传播行为解释适用场景REQUIRED默认有事务就加入没有就新建一个事务最常用比如转账服务REQUIRES_NEW新建一个事务挂起原事务等新事务执行完再继续原事务比如记录日志不管主事务成功失败日志都要记录NESTED嵌套事务有一个保存点1. 子事务回滚只回滚自己不影响父事务和其他子事务2. 父事务回滚带着所有子事务一起回滚系统批量发福利某一个用户的福利发放失败不影响其他用户但整体回滚所有用户的福利都会被收回小贴士Spring AOP 是基于代理的Transactional只能用在 public 方法上不然不生效。不管是 JDK 动态代理还是 CGLIB 代理Spring 都只保证 public 方法的事务生效非 public 的写了也白写。内部调用不会走代理类直接调用this.method()所以同一个类里方法调用Transactional不生效。Spring默认只回滚非受检异常RuntimeException、Error受检异常Exception不回滚。如果要所有异常都回滚需要在Transactional里加rollbackFor Exception.class。MySQL的MyISAM引擎不支持事务只有InnoDB支持。