一.事务的隔离级别:
1.读未提交 (Read uncommitted)就是一个事务可以读取到另一个未提交事务的数据。
例:老板要给员工发工资,员工的工资是1万/月。但是发工资时老板不小心按错了数字,按成1.1万/月,该钱已经打到员工的卡上,但是事务还没有提交,就在这时,员工去查看自己这个月的工资,发现比往常多了1千元,以为涨工资了非常高兴。但是老板及时发现了不对,马上回滚差点就提交了的事务,将数字改成1万再提交。
分析:员工这个月的工资还是1万,但是员工看到的是1.1万。他看到的是老板还没提交事务时的数据,这就是脏读。
2.读已提交 (Read committed)就是一个事务要等另一个事务提交后才能读取数据。
例:员工拿着信用卡去享受生活(卡里当然是只有1万),当他买单时(员工事务开启),收费系统事先检测到他的卡里有1万,就在这个时候!!员工的妻子要把钱全部转出充当家用,并提交。当收费系统准备扣款时,再检测卡里的金额,发现已经没钱了(第二次检测金额当然要等待妻子转出金额事务提交完)。员工就会很郁闷,明明卡里是有钱的…
分析:这就是读已提交,若有事务对数据进行更新(UPDATE)操作时,读操作事务要等待这个更新操作事务提交后才能读取数据,可以解决脏读问题。但在这个事例中,出现了一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读。
3.可重复读 (Repeatable read) 就是在开始读取数据(事务开启)时,不再允许修改操作。
例:员工拿着信用卡去享受生活(卡里当然是只有1万),当他买单时(事务开启,不允许其他事务的UPDATE修改操作),收费系统事先检测到他的卡里有1万。这个时候他的妻子不能转出金额了,接下来收费系统就可以扣款了。
分析:可重复读可以解决不可重复读问题。写到这里,应该明白的一点就是,不可重复读对应的是修改,即UPDATE操作。但是可能还会有幻读问题。因为幻读问题对应的是插入INSERT操作,而不是UPDATE操作。
什么时候会出现幻读?
例:程序员某一天去消费,花了2千元,然后他的妻子去查看他今天的消费记录(全表扫描FTS,妻子事务开启),看到确实是花了2千元,就在这个时候,程序员花了1万买了一部电脑,即新增INSERT了一条消费记录,并提交。当妻子打印程序员的消费记录清单时(妻子事务提交),发现花了1.2万元,似乎出现了幻觉,这就是幻读。
那怎么解决幻读问题?
1.通过对select操作手动加行X锁(SELECT … FOR UPDATE )。原因是InnoDB中行锁锁定的是索引,纵然当前记录不存在,当前事务也会获得一把记录锁(记录存在就加行X锁,不存在就加next-key lock间隙X锁),这样其他事务则无法插入此索引的记录,杜绝幻读。
2.进一步提升隔离级别为SERIALIZABLE
4.可串行化
Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读,但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。
四种隔离级别可能导致的问题:
1.读未提交 :事务中的修改,即使没有提交,其他事务也可以看得到,会导致“脏读”、“幻读”和“不可重复读取”。
2.读已提交:大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”,但不能避免“幻读”和“不可重复读取”。该级别适用于大多数系统。
3.可重复读:保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但不能避免“幻读”,但是带来了更多的性能损失。
4.可串行化:最严格的级别,事务串行执行,资源消耗最大。
事务的七种传播方式:
REQUIRED(默认):支持使用当前事务,如果当前事务不存在,创建一个新事务。
SUPPORTS:支持使用当前事务,如果当前事务不存在,则不使用事务。
MANDATORY:中文翻译为强制,支持使用当前事务,如果当前事务不存在,则抛出Exception。
REQUIRES_NEW:创建一个新事务,如果当前事务存在,把当前事务挂起。
NOT_SUPPORTED:无事务执行,如果当前事务存在,把当前事务挂起。
NEVER:无事务执行,如果当前有事务则抛出Exception。
NESTED:嵌套事务,如果当前事务存在,那么在嵌套的事务中执行。如果当前事务不存在,则表现跟REQUIRED一样。
格式:@Transactional(propagation = Propagation.REQUIRES_NEW)
Spring支持编程式事务管理以及声明式事务管理两种方式
- 编程式事务管理
编程式事务管理是侵入性事务管理,使用TransactionTemplate或者直接使用PlatformTransactionManager,对于编程式事务管理,Spring推荐使用TransactionTemplate。 - 声明式事务管理
声明式事务管理建立在AOP之上,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,执行完目标方法之后根据执行的情况提交或者回滚。
编程式事务每次实现都要单独实现,但业务量大功能复杂时,使用编程式事务无疑是痛苦的,而声明式事务不同,声明式事务属于无侵入式,不会影响业务逻辑的实现,只需要在配置文件中做相关的事务规则声明或者通过注解的方式,便可以将事务规则应用到业务逻辑中。
显然声明式事务管理要优于编程式事务管理,这正是Spring倡导的非侵入式的编程方式。唯一不足的地方就是声明式事务管理的粒度是方法级别,而编程式事务管理是可以到代码块的,但是可以通过提取方法的方式完成声明式事务管理的配置。
本文共 2034 个字数,平均阅读时长 ≈ 6分钟
评论 (0)