事务的ACID
这个先说一下ACID,必须得知道:
(1)Atomic:原子性,就是一堆SQL,要么一起成功,要么都别执行,不允许某个SQL成功了,某个SQL失败了,这就是扯淡,不是原子性。
(2)Consistency:一致性,这个是针对数据一致性来说的,就是一组SQL执行之前,数据必须是准确的,执行之后,数据也必须是准确的。别搞了半天,执行完了SQL,结果SQL对应的数据修改没给你执行,那不是坑爹么。
(3)Isolation:隔离性,这个就是说多个事务在跑的时候不能互相干扰,别事务A操作个数据,弄到一半儿还没弄好呢,结果事务B来改了这个数据,导致事务A的操作出错了,那不就搞笑了。
(4)Durability:持久性,事务成功了,就必须永久对数据的修改是有效的,别过了一会儿数据自己没了,不见了,那就好玩儿了。
事务隔离级别
(1)读未提交,Read Uncommitted:这个很坑爹,就是说某个事务还没提交的时候,修改的数据,就让别的事务给读到了,这就恶心了,很容易导致出错的。这个也叫做脏读。
(2)读已提交,Read Committed(不可重复读):这个比上面那个稍微好一点,但是一样比较尴尬,就是说事务A在跑的时候, 先查询了一个数据是值1,然后过了段时间,事务B把那个数据给修改了一下还提交了,此时事务A再次查询这个数据就成了值2了,这是读了人家事务提交的数据啊,所以是读已提交。这个也叫做不可重复读,就是所谓的一个事务内对一个数据两次读,可能会读到不一样的值。
(3)可重复读,Read Repeatable:这个就是比上面那个再好点儿,就是说事务A在执行过程中,对某个数据的值,无论读多少次都是值1;哪怕这个过程中事务B修改了数据的值还提交了,但是事务A读到的还是自己事务开始时这个数据的值。
(4)串行化:幻读,不可重复读和可重复读都是针对两个事务同时对某条数据在修改,但是幻读针对的是插入,比如某个事务把所有行的某个字段都修改为了2,结果另外一个事务插入了一条数据,那个字段的值是1,然后就尴尬了。第一个事务会突然发现多出来一条数据,那个数据的字段是1。如果要解决幻读,就需要使用串行化级别的隔离级别,所有事务都串行起来,不允许多个事务并行操作。
MySQL的默认隔离级别是Read Repeatable,就是可重复读,就是说每个事务都会开启一个自己要操作的某个数据的快照,事务期间,读到的都是这个数据的快照罢了,对一个数据的多次读都是一样的。
MySQL是通过MVCC机制来实现的,就是多版本并发控制,multi-version concurrency control。 实现可以重复读
Spring的事务支持以及传播特性
(1)PROPAGATION_REQUIRED(默认,支持原事务,如果没有事务就以自己事务为准):这个是最常见的,就是说,如果ServiceA.method调用了ServiceB.method,如果ServiceA.method开启了事务,然后ServiceB.method也声明了事务,那么ServiceB.method不会开启独立事务,而是将自己的操作放在ServiceA.method的事务中来执行,ServiceA和ServiceB任何一个报错都会导致整个事务回滚。这就是默认的行为,其实一般我们都是需要这样子的。
(2)PROPAGATION_SUPPORTS(支持原事务):如果ServiceA.method开了事务,那么ServiceB就将自己加入ServiceA中来运行,如果ServiceA.method没有开事务,那么ServiceB自己也不开事务
(3)PROPAGATION_MANDATORY(调用方法必须有事务):必须被一个开启了事务的方法来调用自己,否则报错
(4)PROPAGATION_REQUIRES_NEW(开启新的事务):ServiceB.method强制性自己开启一个新的事务,然后ServiceA.method的事务会卡住,等ServiceB事务完了自己再继续。这就是影响的回滚了,如果ServiceA报错了,ServiceB是不会受到影响的,ServiceB报错了,ServiceA也可以选择性的回滚或者是提交。
(5)PROPAGATION_NOT_SUPPORTED(不支持事务,不影响事务):就是ServiceB.method不支持事务,ServiceA的事务执行到ServiceB那儿,就挂起来了,ServiceB用非事务方式运行结束,ServiceA事务再继续运行。这个好处就是ServiceB代码报错不会让ServiceA回滚。
(6)PROPAGATION_NEVER(不能被一个事务来调用):不能被一个事务来调用,ServiceA.method开事务了,但是调用了ServiceB会报错
(7)PROPAGATION_NESTED(事务嵌套,回滚自己的事务):开启嵌套事务,ServiceB开启一个子事务,如果回滚的话,那么ServiceB就回滚到开启子事务的这个save point。
Spring aop 事务源码
1.TransactionIntercepor其实就是如果我们给我们的service组件加了@Transactional注解之后,就会对我们的这个service组件里的方法在调用的时候,就会先走这个TransactionoIntercepor的拦截 执行invoke方法
2.执行前 TransactionIntercepor 会先 调用 我们ORM 框架去 beginTransaction 开启事务 然后 调用 我们具体方法
3.根据调用是否异常判断是否回滚和提交 调用TransactionManager 调用对应的方法
使用场景
TCC分布式事务:解决的就是大多数的分布式事务场景,服务链式调用
可靠消息最终一致性方案:重要必须执行成功,但是耗时,可以接受异步化
最大努力通知方案:耗时,可以接受异步化,而且可有可无,可以接受失败不成功
XA规范以及2PC分布式事务理论介绍
有个叫做X/Open的组织定义了分布式事务的模型,这里面有几个角色,就是AP(Application,应用程序),TM(Transaction Manager,事务管理器),RM