SSM框架,程序员首次接触的Java框架,而到现在,随着互联网的发展,单纯的会一个ssm早已经不足以支持你的发展,但是现在,ssm依旧问的比较多,不过,就是问的越来越底层,问的越来越深入,其中,这三兄弟中最让人头疼的就是面试问spring源码,而spring源码中最让人头疼的个人觉得应该就是spring事务了
随意,今天,万字文章,通过代码+图片,讲解spring事务,话不多说,进入正题吧
1. 什么是事务?
事务是逻辑上的一组操作,要么都执行,要么都不执行。
Guide 哥:大家应该都能背上面这句话了,下面我结合我们日常的真实开发来谈一谈。
我们系统的每个业务方法可能包括了多个原子性的数据库操作,比如下面的 savePerson() 方法中就有两个原子性的数据库操作。这些原子性的数据库操作是有依赖的,它们要么都执行,要不就都不执行。
public void savePerson() { personDao.save(person); personDetailDao.save(personDetail); }
另外,需要格外注意的是:事务能否生效数据库引擎是否支持事务是关键。比如常用的 MySQL 数据库默认使用支持事务的innodb引擎。但是,如果把数据库引擎变为 myisam,那么程序也就不再支持事务了!
事务最经典也经常被拿出来说例子就是转账了。假如小明要给小红转账 1000 元,这个转账会涉及到两个关键操作就是:
- 将小明的余额减少 1000 元
- 将小红的余额增加 1000 元。
万一在这两个操作之间突然出现错误比如银行系统崩溃或者网络故障,导致小明余额减少而小红的余额没有增加,这样就不对了。事务就是保证这两个关键操作要么都成功,要么都要失败。
public class OrdersService { private AccountDao accountDao; public void setOrdersDao(AccountDao accountDao) { this.accountDao = accountDao; } @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false, timeout = -1) public void accountMoney() { //小红账户多1000 accountDao.addMoney(1000,xiaohong); //模拟突然出现的异常,比如银行中可能为突然停电等等 //如果没有配置事务管理的话会造成,小红账户多了1000而小明账户没有少钱 int i = 10 / 0; //小王账户少1000 accountDao.reduceMoney(1000,xiaoming); } }
另外,数据库事务的 ACID 四大特性是事务的基础,下面简单来了解一下。
2. 事物的特性(ACID)了解么?
- 原子性: 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
- 一致性: 执行事务前后,数据保持一致;
- 隔离性: 并发访问数据库时,一个用户的事物不被其他事务所干扰也就是说多个事务并发执行时,一个事务的执行不应影响其他事务的执行;
- 持久性: 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
3. 详谈 Spring 对事务的支持
再提醒一次:你的程序是否支持事务首先取决于数据库 ,比如使用 MySQL 的话,如果你选择的是 innodb 引擎,那么恭喜你,是可以支持事务的。但是,如果你的 MySQL 数据库使用的是 myisam 引擎的话,那不好意思,从根上就是不支持事务的。
这里再多提一下一个非常重要的知识点: MySQL 怎么保证原子性的?
我们知道如果想要保证事务的原子性,就需要在异常发生时,对已经执行的操作进行回滚,在 MySQL 中,恢复机制是通过 回滚日志(undo log) 实现的,所有事务进行的修改都会先先记录到这个回滚日志中,然后再执行相关的操作。如果执行过程中遇到异常的话,我们直接利用回滚日志 中的信息将数据回滚到修改之前的样子即可!并且,回滚日志会先于数据持久化到磁盘上。这样就保证了即使遇到数据库突然宕机等情况,当用户再次启动数据库的时候,数据库还能够通过查询回滚日志来回滚将之前未完成的事务。
3.1. Spring 支持两种方式的事务管理
1).编程式事务管理
通过 TransactionTemplate或者TransactionManager手动管理事务,实际应用中很少使用,但是对于你理解 Spring 事务管理原理有帮助。
使用TransactionTemplate 进行编程式事务管理的示例代码如下:
@Autowired private TransactionTemplate transactionTemplate; public void testTransaction() { transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { try { // .... 业务代码 } catch (Exception e){ //回滚 transactionStatus.setRollbackOnly(); } } }); }
使用 TransactionManager 进行编程式事务管理的示例代码如下:
@Autowired private PlatformTransactionManager transactionManager; public void testTransaction() { TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition()); try { // .... 业务代码 transactionManager.commit(status); } catch (Exception e) { transactionManager.rollback(status); } }
2)声明式事务管理
推荐使用(代码侵入性最小),实际是通过 AOP 实现(基于@Transactional 的全注解方式使用最多)。
使用 @Transactional注解进行事务管理的示例代码如下:
@Transactional(propagation=propagation.PROPAGATION_REQUIRED) public void aMethod { //do something B b = new B(); C c = new C(); b.bMethod(); c.cMethod(); }