赞
踩
【自己学习事务做的笔记,方便记忆和复习】
最经典的例子就是银行转账问题,A账户给B账户转账100元,A账户扣除100元后由于不可抗力因素导致程序中断,B账户没有收到那100元,A账户那100元凭空消失,肯定是不行的。A扣款和B收款操作要么同时成功,要么同时失败,这个时候就需要引入事务操作。
spring支持编程式事务管理和声明式事务管理两种方式。
编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。
声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。
@Transactional注解:
它是声明式事务管理编程中使用的注解,放在接口实现类或接口实现方法上,并且只对public方法才起作用。只读的接口不需要事务管理,防止影响系统性能。
@Transactional 实质是使用了 JDBC 的事务来进行事务控制的,实现原理:
事务开始时,通过AOP机制,生成一个代理connection对象,并将其放入 DataSource 实例的某个与 DataSourceTransactionManager 相关的某处容器中。在接下来的整个事务中,客户代码都应该使用该 connection 连接数据库,执行所有数据库命令。[不使用该 connection 连接数据库执行的数据库命令,在本事务回滚的时候得不到回滚](物理连接 connection 逻辑上新建一个会话session;DataSource 与 TransactionManager 配置相同的数据源)
事务结束时,回滚在第1步骤中得到的代理 connection 对象上执行的数据库命令,然后关闭该代理 connection 对象。(事务结束后,回滚操作不会对已执行完毕的SQL操作命令起作用)
当多个线程都开启事务操作数据库中的数据时,数据库系统要能进行隔离操作,以保证各个线程获取数据的准确性。隔离级别越高,数据库的并发性能就越差。
在该隔离级别下,所有事务都可以看到其它未提交事务的执行结果。即在该级别下,事务的修改即便没有提交,对其他事务也都是可见的,可能出现脏读、不可重复读、幻读。
该隔离级别满足了隔离的简单定义,一个事务只能看见已经提交事务所做的改变。这是Oracle数据库默认的事务隔离级别。避免了脏读,可能出现不可重复读、幻读。
可以确保同一个事务在多次读取同样的数据时,返回同样的结果。这是MySQL数据库默认的事务隔离级别。这样避免了不可重复读和脏读,但是有时可能会出现幻读。
它通过强制事务排序,使事务一个一个的进行,事务之间不可能再存在相互冲突,从而解决幻读问题。
脏读、不可重复读、幻读:
1、脏读
脏读就是指当A事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,B事务也访问这个数据,然后使用了这个数据。这时候如果事务A回滚,那么B事务读到的数据是不被承认的。
2、不可重复读(重点在修改,体现在值不同)
指在A事务内,多次读同一数据。在A事务还没有结束时,B事务也访问该同一数据。那么,在A事务中的两次读数据之间,由于B事务的修改,那么A事务两次读到的的数据可能是不一样的。这样就发生了在A事务内两次读到的数据是不一样的。
3、幻读(重点在增加或删除,体现在记录数不同)
是指当事务不是独立执行时发生的一种现象,例如A事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,B事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作A事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
@Transactional(propagation = Propagation.REQUIRED)
spring中的默认事务传播行为就是它。如果业务方法执行时已经在一个事务中,则加入当前事务,
否则重新开启一个事务。外层事务提交了,内层才会提交。内/外只要有报错,他俩会一起回滚。
只要内层方法报错抛出异常,即使外层有try-catch,该事务也会回滚。
因为内外层方法在同一个事务中,内层只要抛出了异常,这个事务就会被设置成rollback-only,即使外层try-catch内层的异常,该事务也会回滚。
@Transactional(propagation = Propagation.REQUIRES_NEW)
支持事务。每次都是创建一个新事物,如果当前已经在事务中了,会挂起当前事务。内层事务结束,内层就提交了,不用等着外层一起提交。
外层报错回滚,不影响内层。内层报错回滚,外层try-catch内层的异常,外层不会回滚。
内层报错回滚,然后又会抛出异常,外层如果没有捕获处理内层抛出来的这个异常,外层还是会回滚的。
@Transactional(propagation = Propagation.NESTED)
支持事务。如果当前事务存在,那么在嵌套的事务中执行,内层事务结束,要等着外层一起提交。如果当前事务不存在,则表现跟REQUIRED一样。
这个直接说,如果外层报错回滚,内层也会跟着回滚。
如果只是内层回滚,不影响外层。这个内层回滚不影响外层的特性是有前提的,否则内外都回滚。
内层是NESTED模式下,外层要try-catch内层的异常,外层才不会回滚。而内层是REQUIRED模式的话,即使外层try-catch内层异常,外层同样会回滚的。
@Transactional(propagation = Propagation.SUPPORTS)
支持事务。当前有事务就支持使用当前事务,若当前不存在事务,以非事务的方式执行。内层事务结束,要等着外层一起提交。
@Transactional(propagation = Propagation.MANDATORY)
支持事务,如果业务方法执行时已经在一个事务中,则加入当前事务。否则抛出异常。内层事务结束,要等着外层一起提交。
@Transactional(propagation = Propagation.NOT_SUPPORTED)
不支持事务,以非事务的方式执行,若当前存在事务,则把当前事务挂起,等方法执行完毕后,事务恢复进行。
若A是事务执行,B(NOT_SUPPORTED非事务执行)B在A尚未提交前再操作同一条记录,会产生死锁,A、B不可操作同一条记录。
@Transactional(propagation = Propagation.NEVER)
不支持事务。如果当前已经在一个事务中了,抛出异常。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。